mongodb/mongoose的findMany - 查找所有在数组中列出的ID的文档

358
我有一个 _ids 数组,希望能够相应地获取所有文档,最好的方法是什么?类似于...
// doesn't work ... of course ...

model.find({
    '_id' : [
        '4ed3ede8844f0f351100000c',
        '4ed3f117a844e0471100000d', 
        '4ed3f18132f50c491100000e'
    ]
}, function(err, docs){
    console.log(docs);
});

这个数组可能包含数百个_id。

9个回答

654

find函数在Mongoose中是对MongoDB的完整查询。这意味着您可以使用方便的MongoDB $in子句,其与SQL版本的作用相同。

model.find({
    '_id': { $in: [
        mongoose.Types.ObjectId('4ed3ede8844f0f351100000c'),
        mongoose.Types.ObjectId('4ed3f117a844e0471100000d'), 
        mongoose.Types.ObjectId('4ed3f18132f50c491100000e')
    ]}
}, function(err, docs){
     console.log(docs);
});

即使数组包含数万个ID,这种方法也能很好地运作。 (参见Efficiently determine the owner of a record)

我建议任何使用 mongoDB 的人都应该阅读优秀的官方mongoDB文档中的高级查询部分。


23
虽然来晚了,但你如何确保返回的项目顺序与提供的数组顺序一致?除非指定排序,否则不能保证文档按任何顺序输出。如果希望按照数组中列出的相同顺序进行排序(例如...000c,...000d,...000e),该怎么办? - Kevin
10
由于某些原因,这并没有起作用。我得到了一个空的文档数组。 - chovy
3
请先尝试将它们转换为ObjectIds,而不是传递字符串。可以参考此链接:https://dev59.com/nWw15IYBdhLWcg3wfb3i - Georgi Hristozov
2
@Kevin 你可能会对这个答案感兴趣:https://dev59.com/umEh5IYBdhLWcg3wHAND#22800784 - user133408
2
@Schybo 这完全没有区别。{ _id : 5 }{ '_id' : 5 } 是一样的。 - royhowie
显示剩余3条评论

167

Ids是对象id的数组:

const ids =  [
    '4ed3ede8844f0f351100000c',
    '4ed3f117a844e0471100000d', 
    '4ed3f18132f50c491100000e',
];

使用回调函数与Mongoose:

Model.find().where('_id').in(ids).exec((err, records) => {});

使用 async 函数与 Mongoose:

const records = await Model.find().where('_id').in(ids).exec();

更简洁地说:

const records = await Model.find({ '_id': { $in: ids } });

不要忘记将 Model 替换为您实际的模型。


10
这应该被接受作为答案,因为它是最新和最连贯的答案。您不必像已接受的答案那样将ID转换为ObjectId,并且它使用mongoose命令式风格的查询。顺便说一句,谢谢! - Javi Marzán
这是一个非常干净和更新的方法,如果您不介意,我想问几个问题。假设我有一个引用了ObjectId的数组(比如说,我有一些项目,并且我将某些项目分配给了特定的用户,其中在用户模型上引用了项目ID),如果我删除一个项目,我该如何确保从用户模型引用的数组中删除该id?谢谢Mat。 - Eazy
这正是我所需要的!它干净易用,其中的ID在另一个模型中是引用。 - tarafenton
这个很好用!为了获得一个优化版本,你可以在末尾添加 .lean(),它将只返回 POJO(普通的 JavaScript 对象)。你还可以添加 select() 并仅选择文档中所需的字段。 - Himanshu Tariyal

23

结合Daniel和snnsnn的回答:

let ids = ['id1', 'id2', 'id3'];
let data = await MyModel.find({
  '_id': { 
    $in: ids
  }
});

简洁清晰的代码。它经过测试并可用于:

"mongodb": "^3.6.0",
"mongoose": "^5.10.0",

1
我一直把ID放在数组括号“[]”里,但从你的回答中意识到它已经是一个数组了 :| - Riza Khan
@RizaKhan 非常感谢你!我犯了完全相同的错误。 - fIwJlxSzApHEZIl

13

使用这种查询格式

let arr = _categories.map(ele => new mongoose.Types.ObjectId(ele.id));

Item.find({ vendorId: mongoose.Types.ObjectId(_vendorId) , status:'Active'})
  .where('category')
  .in(arr)
  .exec();

10

在我的环境下,这段代码适用于mongoDB v4.2和mongoose 5.9.9:

const Ids = ['id1','id2','id3']
const results = await Model.find({ _id: Ids})

而Id的类型可以是ObjectIdString


6

无论是node.js还是MongoChef都要求我进行ObjectId转换。这是我从数据库中获取用户列表并获取一些属性的代码。请注意第8行的类型转换。

// this will complement the list with userName and userPhotoUrl 
// based on userId field in each item
augmentUserInfo = function(list, callback) {
    var userIds = [];
    var users = [];         // shortcut to find them faster afterwards

    for (l in list) {       // first build the search array
        var o = list[l];

        if (o.userId) {
            userIds.push(new mongoose.Types.ObjectId(o.userId)); // for Mongo query
            users[o.userId] = o; // to find the user quickly afterwards
        }
    }

    db.collection("users").find({
        _id: {
            $in: userIds
        }
    }).each(function(err, user) {
        if (err) {
            callback(err, list);
        } else {
            if (user && user._id) {
                users[user._id].userName = user.fName;
                users[user._id].userPhotoUrl = user.userPhotoUrl;
            } else { // end of list
                callback(null, list);
            }
        }
    });
}

7
userIds = .map(list, function(userId){ return mongoose.Types.ObjectId(userId) }); 翻译:将list中的每个userId转换成mongoose.Types.ObjectId对象,并返回对象数组赋值给userIds。其中,underscore.js库的.map()函数用来遍历list中的每个元素,function(userId){ return mongoose.Types.ObjectId(userId) }是一个回调函数,将每个userId转换成对应的ObjectId对象。 - Michael Draper
1
我不需要使用mongoose 4.5.9将其转换为ObjectID。 - Florian Wendelborn

6
如果您正在使用async-await语法,可以使用
const allPerformanceIds = ["id1", "id2", "id3"];
const findPerformances = await Performance.find({ 
    _id: { 
        $in: allPerformanceIds 
    } 
});           

4

我尝试了以下方法,对我有效。

var array_ids = [1, 2, 6, 9]; // your array of ids

model.find({ 
    '_id': { 
        $in: array_ids 
    }
}).toArray(function(err, data) {
    if (err) {
        logger.winston.error(err);
    } else {
        console.log("data", data);
    }
});

-1
我正在使用这个查询来查找Mongo GridFs中的文件。我想通过它们的ID获取它们。
对我来说,这个解决方案是有效的:Ids类型为ObjectId
gfs.files
.find({ _id: mongoose.Types.ObjectId('618d1c8176b8df2f99f23ccb') })
.toArray((err, files) => {
  if (!files || files.length === 0) {
    return res.json('no file exist');
  }
  return res.json(files);
  next();
});

这个不行:Id类型的字符串
gfs.files
.find({ _id: '618d1c8176b8df2f99f23ccb' })
.toArray((err, files) => {
  if (!files || files.length === 0) {
    return res.json('no file exist');
  }
  return res.json(files);
  next();
});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接