Mongodb - 从集合中删除没有唯一值的文档
Mongodb - delete docs from collection that do not have unique value
我收集了这样的对象:
{"_id":"...", "user":"foo", "value":"a"}, // this one stays coz its user is foo
{"_id":"...", "user":"bar", "value":"a"}, // remove this one
{"_id":"...", "user":"baz", "value":"a"}, // remove this one
{"_id":"...", "user":"qux", "value":"b"}, // this one has unique value so it doesn't get deleted
我想查找并删除所有具有重复值的对象,除非用户是 foo
。
是否有 JS mongoshell 方法?
好的,这还没有经过测试,但是你开始吧...这是假设使用 Mongoose 与数据库交互...
let values = [];
let deleteIds = [];
myModel.find({}).then(docs => {
docs.forEach(d => {
if (values.indexOf(d.value)) {
deleteIds.push(d._id);
} else {
values.push(d.value);
}
})
deleteIds.forEach(id => {
myModel.findOneAndRemove({_id: id});
});
});
我使用这段代码修复了这个问题(这不是此功能的完整代码):
let query = {
user:targetedUser
}
let projection = {
_id:0, id:1, user:1
}
collection.find(query, projection)
.on('data', doc => {
collection.deleteMany({id:doc.id, user: {$not: new RegExp(targetedUser)}})
})
.on('end', _=> {
db.close()
})
基本上 targetedUser
变量是您要保留的对象的值,同时删除所有其他重复的且与该值不匹配的对象。查看它,删除其他用户的所有重复项,同时为特定用户保留它们。
这是非常特殊的情况,对于常见问题可能有所不同。但是这个答案的重点是,这段代码可能看起来会吃掉所有的 RAM,但与我迄今为止尝试过的其他实现相比,它不会占用超过 20MB 的 300 万条记录,而且速度很快.
这是我在 mongoDB 中获取重复项的看法。 aggregate
是一个很有帮助的函数。您可以应用多个管道到达您想要的位置。 aggregate
- 匹配所有不等于 foo 的用户
- 将它们按
value
分组,这将是 _id
并增加在文档集中找到的每个 $_id
(原始)的计数。将项目推送到名为 docIds
. 的数组中
- 从这个新集合中获取所有 rows/docs 的 $count > 1
- 放松(请查看文档以获得更好的解释)
这将为您提供 value
出现不止一次的文档。一旦您对结果集感到满意,您就可以对这些文档执行删除操作。我没有手动 运行 这个...让我们知道..
db.collection.aggregate([{
$match: {
"user": {
$ne: "foo"
}
}
}, {
$group: {
_id: "$value",
docIds: {
$push: "$_id"
},
count: {
$sum: 1
}
}
}, {
$match: "$count": {
$gt: 1
}
}, {
$unwind: $docIds
}
])
我收集了这样的对象:
{"_id":"...", "user":"foo", "value":"a"}, // this one stays coz its user is foo
{"_id":"...", "user":"bar", "value":"a"}, // remove this one
{"_id":"...", "user":"baz", "value":"a"}, // remove this one
{"_id":"...", "user":"qux", "value":"b"}, // this one has unique value so it doesn't get deleted
我想查找并删除所有具有重复值的对象,除非用户是 foo
。
是否有 JS mongoshell 方法?
好的,这还没有经过测试,但是你开始吧...这是假设使用 Mongoose 与数据库交互...
let values = [];
let deleteIds = [];
myModel.find({}).then(docs => {
docs.forEach(d => {
if (values.indexOf(d.value)) {
deleteIds.push(d._id);
} else {
values.push(d.value);
}
})
deleteIds.forEach(id => {
myModel.findOneAndRemove({_id: id});
});
});
我使用这段代码修复了这个问题(这不是此功能的完整代码):
let query = {
user:targetedUser
}
let projection = {
_id:0, id:1, user:1
}
collection.find(query, projection)
.on('data', doc => {
collection.deleteMany({id:doc.id, user: {$not: new RegExp(targetedUser)}})
})
.on('end', _=> {
db.close()
})
基本上 targetedUser
变量是您要保留的对象的值,同时删除所有其他重复的且与该值不匹配的对象。查看它,删除其他用户的所有重复项,同时为特定用户保留它们。
这是非常特殊的情况,对于常见问题可能有所不同。但是这个答案的重点是,这段代码可能看起来会吃掉所有的 RAM,但与我迄今为止尝试过的其他实现相比,它不会占用超过 20MB 的 300 万条记录,而且速度很快.
这是我在 mongoDB 中获取重复项的看法。 aggregate
是一个很有帮助的函数。您可以应用多个管道到达您想要的位置。 aggregate
- 匹配所有不等于 foo 的用户
- 将它们按
value
分组,这将是_id
并增加在文档集中找到的每个$_id
(原始)的计数。将项目推送到名为docIds
. 的数组中
- 从这个新集合中获取所有 rows/docs 的 $count > 1
- 放松(请查看文档以获得更好的解释)
这将为您提供 value
出现不止一次的文档。一旦您对结果集感到满意,您就可以对这些文档执行删除操作。我没有手动 运行 这个...让我们知道..
db.collection.aggregate([{
$match: {
"user": {
$ne: "foo"
}
}
}, {
$group: {
_id: "$value",
docIds: {
$push: "$_id"
},
count: {
$sum: 1
}
}
}, {
$match: "$count": {
$gt: 1
}
}, {
$unwind: $docIds
}
])