366

I have an array of _ids and I want to get all docs accordingly, what's the best way to do it ?

Something like ...

// doesn't work ... of course ...

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

The array might contain hundreds of _ids.

10 Answers 10

664

The find function in mongoose is a full query to mongoDB. This means you can use the handy mongoDB $in clause, which works just like the SQL version of the same.

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

This method will work well even for arrays containing tens of thousands of ids. (See Efficiently determine the owner of a record)

I would recommend that anybody working with mongoDB read through the Advanced Queries section of the excellent Official mongoDB Docs

Sign up to request clarification or add additional context in comments.

8 Comments

Kind of late to this discussion, but how would you ensure the order of the items returned matches the order of the array of items you provide in the array? Documents are not guaranteed to come out in any order unless you specify a sort. What if you want them sorted in the same order you list them in the array (e.g. ...000c, ...000d, ...000e)?
This did not work for some reason. I got an empty array of docs
@chovy try converting them to ObjectIds first, instead of passing strings.
@Kevin You might be interested in this answer: stackoverflow.com/a/22800784/133408
@Schybo that makes absolutely no difference. { _id : 5 } is the same as { '_id' : 5 }.
|
176

Ids is the array of object ids:

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

Using Mongoose with callback:

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

Using Mongoose with async function:

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

Or more concise:

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

Don't forget to change Model with your actual model.

4 Comments

This should be the accepted answer as it is the most up to date and coherent one. You don't have to convert the ids to ObjectId as in the accepted answer, and it uses the mongoose imperative style queries. Thanks btw!
This is a very clean and updated method, if you don't mind I'd like to ask a few question, if I have an array of referenced ObjectId's like the above (say, I have projects, and I assigned an array of projects to certain users with the project_id referenced on the user model), if I delete a project, how do I make sure the id is deleted from the array referenced from the user model ? Thanks mat.
this is what I needed! It's clean and easy to use with ids that are a ref in another model
This works well ! For an optimized version, you can attach .lean() at the end which will return only POJO ( Plain Old Javascript Object ). You can also add select() and pick only the required fields of the document.
24

Combining Daniel's and snnsnn's answers:

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

Simple and clean code. It works and tested against:

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

2 Comments

I kept putting the ids inside of array brackets [] but realized from your answer that it is already an array :|
@RizaKhan thank you so much! I made the same exact mistake.
13

Use this format of querying

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();

Comments

10

This code works for me just fine as of mongoDB v4.2 and mongoose 5.9.9:

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

and the Ids can be of type ObjectId or String

Comments

8

if you are using the async-await syntax you can use

const allPerformanceIds = ["id1", "id2", "id3"];
const findPerformances = await Performance.find({ 
    _id: { 
        $in: allPerformanceIds 
    } 
});           

Comments

6

Both node.js and MongoChef force me to convert to ObjectId. This is what I use to grab a list of users from the DB and fetch a few properties. Mind the type conversion on line 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);
            }
        }
    });
}

2 Comments

userIds = _.map(list, function(userId){ return mongoose.Types.ObjectId(userId) };
I didn't have to convert to ObjectID using mongoose 4.5.9.
4

I tried like below and it works for me.

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);
    }
});

Comments

0

The answers above don't work for mongodb 6. My workaround ;

import { ObjectId } from "mongodb";

const ids = ["6786b6789020e854f0099c0a", "6786b6789020e854f0099c0b"]
const userList = await db.collection("user")
    .find({ _id: { $in: ids.map(_id => ObjectId.createFromHexString(_id)) } })
    .toArray();

Comments

-1

I am using this query to find the files in mongo GridFs. I wanted to get the by its Ids.

For me this solution is working: Ids type of 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();
});

This is not working: Id type of string

gfs.files
.find({ _id: '618d1c8176b8df2f99f23ccb' })
.toArray((err, files) => {
  if (!files || files.length === 0) {
    return res.json('no file exist');
  }
  return res.json(files);
  next();
});

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.