如何获取 MongoDB 中所有文档 ID 的数组?我只需要一组 id 而不是文档内容。
8 回答
您可以在 Mongo shell 中通过调用map
光标来执行此操作,如下所示:
var a = db.c.find({}, {_id:1}).map(function(item){ return item._id; })
结果是一个仅包含值a
的数组。_id
它在 Node 中的工作方式是相似的。
(这是 MongoDB 节点驱动程序v2.2
和节点v6.7.0
)
db.collection('...')
.find(...)
.project( {_id: 1} )
.map(x => x._id)
.toArray();
记住要放在map
前面 toArray
,因为这map
不是 JavaScriptmap
函数,而是 MongoDB 提供的函数,它在返回游标之前在数据库中运行。
一种方法是简单地使用 runCommand API。
db.runCommand ( { distinct: "distinct", key: "_id" } )
这给了你这样的东西:
{
"values" : [
ObjectId("54cfcf93e2b8994c25077924"),
ObjectId("54d672d819f899c704b21ef4"),
ObjectId("54d6732319f899c704b21ef5"),
ObjectId("54d6732319f899c704b21ef6"),
ObjectId("54d6732319f899c704b21ef7"),
ObjectId("54d6732319f899c704b21ef8"),
ObjectId("54d6732319f899c704b21ef9")
],
"stats" : {
"n" : 7,
"nscanned" : 7,
"nscannedObjects" : 0,
"timems" : 2,
"cursor" : "DistinctCursor"
},
"ok" : 1
}
distinct
但是,使用实际API有更好的方法:
var ids = db.distinct.distinct('_id', {}, {});
它只是给你一个 id 数组:
[
ObjectId("54cfcf93e2b8994c25077924"),
ObjectId("54d672d819f899c704b21ef4"),
ObjectId("54d6732319f899c704b21ef5"),
ObjectId("54d6732319f899c704b21ef6"),
ObjectId("54d6732319f899c704b21ef7"),
ObjectId("54d6732319f899c704b21ef8"),
ObjectId("54d6732319f899c704b21ef9")
]
不确定第一个版本,但 Node.js 驱动程序肯定支持后者(我看到你提到你想使用它)。看起来像这样:
db.collection('c').distinct('_id', {}, {}, function (err, result) {
// result is your array of ids
})
我还想知道如何使用 MongoDB Node.JS 驱动程序来执行此操作,例如 @user2793120。其他人说他应该用 .each 遍历结果,这对我来说似乎效率很低。我改为使用MongoDB 的聚合:
myCollection.aggregate([
{$match: {ANY SEARCHING CRITERIA FOLLOWING $match'S RULES} },
{$sort: {ANY SORTING CRITERIA, FOLLOWING $sort'S RULES}},
{$group: {_id:null, ids: {$addToSet: "$_id"}}}
]).exec()
排序阶段是可选的。如果您想要所有集合的 _id,则匹配一个。如果您 console.log 结果,您会看到如下内容:
[ { _id: null, ids: [ '56e05a832f3caaf218b57a90', '56e05a832f3caaf218b57a91', '56e05a832f3caaf218b57a92' ] } ]
然后在其他地方使用 result[0].ids 的内容。
这里的关键部分是$group 部分。您必须为 _id 定义一个 null 值(否则,聚合将崩溃),并创建一个包含所有 _id 的新数组字段。如果您不介意重复的 id(根据您在 $match 阶段使用的搜索条件,并假设您正在对 _id 以外的字段进行分组,该字段也有另一个文档 _id),您可以使用$push而不是$addToSet。
在 mongo 控制台上执行此操作的另一种方法可能是:
var arr=[]
db.c.find({},{_id:1}).forEach(function(doc){arr.push(doc._id)})
printjson(arr)
希望有帮助!!!
谢谢!!!
我为此苦苦挣扎了很长时间,我正在回答这个问题,因为我有一个重要的提示。很明显:
db.c.find({},{_id:1});
将是答案。
它奏效了,有点。它将找到前 101 个文档,然后应用程序将暂停。我没有让它继续下去。这既是在使用 MongoOperations 的 Java 中,也是在 Mongo 命令行中。
我查看了 mongo 日志,发现它正在对大量大型文档进行 colscan。我想,疯了,我正在投影总是被索引的_id,那么它为什么要尝试colscan呢?
我不知道为什么会这样做,但解决方案很简单:
db.c.find({},{_id:1}).hint({_id:1});
或在 Java 中:
query.withHint("{_id:1}");
然后它可以使用流样式正常进行:
createStreamFromIterator(mongoOperations.stream(query, MortgageDocument.class)).
map(MortgageDocument::getId).forEach(transformer);
Mongo 可以做一些好事,但它也可能陷入非常混乱的状态。至少这是我迄今为止的经验。
尝试使用聚合管道,如下所示:
db.collection.aggregate([
{ $match: { deletedAt: null }},
{ $group: { _id: "$_id"}}
])
这将返回具有此结构的文档数组
_id: ObjectId("5fc98977fda32e3458c97edd")
我有类似的要求来获取具有 50+ 百万行的集合的 ID。我尝试了很多方法。结果证明,获取 id 的最快方法是仅使用 id 进行 mongoexport。
上面的一个例子对我有用,只是稍作调整。我省略了第二个对象,因为我尝试使用我的 Mongoose 模式。
const idArray = await Model.distinct('_id', {}, function (err, result) {
// result is your array of ids
return result;
});