这是我的架构的设计。 (显示1个文件,数据总计数千)。一切都在同一个系列中。
文件1:
{
pageNumber: 0,
results: [
{
jobkey: "AAA",
},
{
jobkey: "BBB",
},
{
jobkey: "CCC",
}
]
}
文件2:
{
pageNumber: 0,
results: [
{
jobkey: "RRR",
},
{
jobkey: "VVV",
},
{ //This Entire Object needs to be removed
jobkey: "AAA", //Duplicate jobkey value of document 1
//remaining objects in array should stay
}
]
}
每个文档都有一个结果键,它接收一个对象数组。这些对象中的每一个都有一个jobkey和相应的值。在给定的结果数组中,没有两个jobkeys具有相同的值。
问题:
每当jobkey值在数据库中出现多次时,我都需要删除其中一个重复对象。多个结果数组中可能存在相同的jobkey值。
我一直无法找到在mongo shell或mongoose中完成此操作的方法。
答案 0 :(得分:1)
这对我来说似乎是一个奇怪的“重复”定义,因为这些值实际上是在单独的文档中。接下来,如果没有实质性地查询整个集合,在将其添加到目标文档之前查看该值是否存在于任何文档中,您将无法在未来的操作中强制执行此操作。
为了检测并删除“重复”,你必须采取这样的操作:
db.collection.aggregate([
// Match only where array has content
{ "$match": { "results.0": "$exists } },
// Unwind the array
{ "$unwind": "$results" },
// Group the keys with counts keep the doc _id's
{ "$group": {
"_id": "$results.jobkey",
"_ids": { "$push": "$_id" },
"count": { "$sum": 1 }
}},
// Filter only duplicate matches
{ "$match": { "count": { "$gt": 1 } }
]).forEach(function(doc) {
doc._ids.shift(); // remove the first element
db.collection.update(
{ "_id": { "$in": doc._ids } },
{ "$pull": { "results": { "jobkey": doc._id } } },
{ "multi": true }
)
})
基本上确定您认为是“重复”的术语列表,然后迭代该列表以删除其他文档的数组中的文档,这些文档被认为包含另一个文档中存在的一个“重复”。 / p>
这也正在任意判断发现“重复”值的“第一”文档是需要保留的位置。您可以在$sort
之前添加$group
,如果您要保留它的位置与其他一组规则相匹配。
保留列表是因为只有那些不是“第一”文档的文档才是您要更新的文档。当然,后来的$match
过滤掉了在分组键中只出现一次相同值的任何结果。
在迭代这些结果时,您只需从列表中“删除”该“第一个”文档_id
,因为这是您保留的文档。后续.update()
操作仅匹配列表中的“重复”文档。语句的“更新”部分使用$pull
将与指定值匹配的数组元素移除到查询匹配的所有文档中的jobkey。
如果您的目的是保持这些子文档元素具有“唯一”的jobkey值,那么您的用例可能更适合将这些文档存储在另一个集合中,并且只保留对父级数组中的那些文档的引用。在单独的集合中,您可以在索引上使用“唯一约束”来阻止插入重复值。