如何在mongodb中删除列表中的重复值
我有一个mongodb收藏。当我这样做的时候如何在mongodb中删除列表中的重复值,mongodb,mongodb-query,pymongo,aggregation-framework,Mongodb,Mongodb Query,Pymongo,Aggregation Framework,我有一个mongodb收藏。当我这样做的时候 db.bill.find({}) 我知道 { “_id”:ObjectId(“55695ea145e8a960bef8b87a”), “名称”:“ABC.Net”, “代码”:“1-98tfv”, “缩写”:“ABC”, “法案代码”:[190215、44124、190215、147708], “客户名称”:“abc” } 我需要一个操作来删除账单代码中的重复值。最后应该是 { “_id”:ObjectId(“55695ea145e8a960be
db.bill.find({})
我知道
{
“_id”:ObjectId(“55695ea145e8a960bef8b87a”),
“名称”:“ABC.Net”,
“代码”:“1-98tfv”,
“缩写”:“ABC”,
“法案代码”:[190215、44124、190215、147708],
“客户名称”:“abc”
}
我需要一个操作来删除账单代码中的重复值。最后应该是
{
“_id”:ObjectId(“55695ea145e8a960bef8b87a”),
“名称”:“ABC.Net”,
“代码”:“1-98tfv”,
“缩写”:“ABC”,
“法案代码”:[190215、44124、147708],
“客户名称”:“abc”
}
如何在mongodb中实现这一点。您可以使用聚合框架实现这一点,如下所示:
collection.aggregate([
{“$project”:{
“名称”:1,
"守则":一,,
“缩写”:1,
“bill_代码”:{“$setUnion”:[“$bill_代码”,[]]
}}
])
操作员是一个“设置”操作员,因此,要进行“设置”,则只保留“唯一”项
如果您仍在使用早于2.6的MongoDB版本,则必须使用$unwind
和$addToSet
执行此操作:
collection.aggregate([
{“$unwind”:“$bill_codes”},
{“$组”:{
“\u id”:“$\u id”,
“名称”:{“$first”:“$name”},
“代码”:{“$first”:“$code”},
“缩写”:{“$first”:“$缩写”},
“账单代码”:{“$addToSet”:“$bill_代码”}
}}
])
虽然效率不高,但从2.2版开始就支持运算符
当然,如果您真的想永久性地修改集合文档,那么您可以在此基础上展开并相应地处理每个文档的更新。您可以从.aggregate()
中检索“游标”,但基本上遵循以下shell示例:
db.collection.aggregate([
{“$project”:{
“bill_代码”:{“$setUnion”:[“$bill_代码”,[]},
“相同”:{“$eq”:[
{“$size”:“$bill_code”},
{“$size”:{“$setUnion”:[“$bill_codes”,[]]}
]}
}},
{“$match”:{“same”:false}
]).forEach(功能(文档){
db.collection.update(
{u id:doc.\u id},
{“$set”:{“bill_code”:doc.bill_code}
)
})
对于早期版本,需要更多的参与:
db.collection.aggregate([
{“$unwind”:“$bill_codes”},
{“$组”:{
“_id”:{
“\u id”:“$\u id”,
“账单代码”:“$账单代码”
},
“origSize”:{“$sum”:1}
}},
{“$组”:{
“\u id”:“$\u id.\u id”,
“票据代码”:{“$push”:“$\u id.bill\u code”},
“origSize”:{“$sum”:“$origSize”},
“newSize”:{“$sum”:1}
}},
{“$project”:{
“法案代码”:1,
“相同”:{“$eq”:[“$origSize”,“$NEWSSIZE”]}
}},
{“$match”:{“same”:false}
]).forEach(功能(文档){
db.collection.update(
{u id:doc.\u id},
{“$set”:{“bill_code”:doc.bill_code}
)
})
与其中添加的操作一起比较“消除重复”数组是否与原始数组长度相同,并仅返回那些删除了“重复项”以便在更新时处理的文档
可能还应该在这里添加“for python”注释。如果您不关心“识别”包含重复数组项的文档,并且准备用更新“爆破”整个集合,那么只需在客户端代码中使用python来删除重复项: 集合中的文档的
。查找():
collection.update(
{u id:doc[“\u id”]},
{“$set”:{“账单代码”:列表(set(doc[“账单代码”)}
)
所以这很简单,这取决于哪个是更大的危害,查找具有副本的文档或更新每个文档(无论是否需要)的成本
这至少涵盖了一些技术。您可以将foreach循环与一些javascript一起使用:
db.bill.find().forEach(function(entry){
var arr = entry.bill_codes;
var uniqueArray = arr.filter(function(elem, pos) {
return arr.indexOf(elem) == pos;
});
entry.bill_codes = uniqueArray;
db.bill.save(entry);
})
Mongo 3.4+具有聚合阶段,允许您避免显式列出$project
中的所有其他字段:
db.bill.aggregate([
{"$addFields": {
"bill_codes": {"$setUnion": ["$bill_codes", []]}
}}
])
仅供参考,以下是另一种(更冗长的)使用方式,也不需要列出所有可能的字段:
db.bill.aggregate([
{'$unwind': {
'path': '$bill_codes',
// output the document even if its list of books is empty
'preserveNullAndEmptyArrays': true
}},
{'$group': {
'_id': '$_id',
'bill_codes': {'$addToSet': '$bill_codes'},
// arbitrary name that doesn't exist on any document
'_other_fields': {'$first': '$$ROOT'},
}},
{
// the field, in the resulting document, has the value from the last document merged for the field. (c) docs
// so the new deduped array value will be used
'$replaceRoot': {'newRoot': {'$mergeObjects': ['$_other_fields', "$$ROOT"]}}
},
{'$project': {'_other_fields': 0}}
])
MongoDB 4.2收集方法的更新参数也可以是聚合管道(而不是文档)。管道支持
$set
、$unset
和$replaceWith
阶段。使用$setcrossion
聚合管道操作符和$set
阶段,您可以从数组字段中删除重复项,并在单个操作中更新集合
例如:
阵列集合:
来自mongo shell:
更新的阵列集合:
其他更新方法,
update()
、updateOne()
和findAndModify()
也具有此功能。这不会保存回集合。我的意思是再次执行db.bill.find({})
将检索副本value@user567797您的问题没有说明您想更改存储的文档。这是用“仅显示”来回答的。您必须处理结果,并在项目实际更改的位置分别更新每个文档。添加了有关如何执行此操作以及如何识别已从阵列中删除重复项的文档的说明,因此,您不需要更新集合中的每个文档。当我使用mongo 2.4版时,如何使用第二个查询进行更新。还要注意,您的更新代码缺少逗号。@user567797很可能添加了执行此操作的方法和更正。MongoDB 2.4确实很老了,您应该考虑至少升级到2.6.x(在进一步升级之前您必须这样做)。这样做有很多好处,包括
{ "_id" : 0, "a" : [ 3, 5, 5, 3 ] }
{ "_id" : 1, "a" : [ 1, 2, 3, 2, 4 ] }
db.arrays.updateMany(
{ },
[
{ $set: { a: { $setIntersection: [ "$a", "$a" ] } } }
]
)
{ "_id" : 0, "a" : [ 3, 5 ] }
{ "_id" : 1, "a" : [ 1, 2, 3, 4 ] }