Search code examples
mongodbquery-optimizationnosql

Is there a way to map array of _id's to documents in one query using MongoDB?


I have a MongoDB database and 2 collections inside it: programs and exercises. Documents inside programs collection have an exercises field that contains a string representation of IDs in exercises table, like that:

{
    "_id" : ObjectId("57da8f955cf29df682932ee9"),
      "exercises" : [ 
          "57da8e01d0649e646afaea4e", 
          "57da8e01d0649e646afaea4e", 
          "57da8e01d0649e646afaea4e"
      ]
}

I need to map this array of IDs to array of related exercises objects. The thing is, I need then in precise order and including duplicates. Like in that document earlier, it contains 3 links to the same exercise, and I need to get an array of 3 identical exercises in response.

Now I am using this query:

db.collection("exercises").find({_id: {$in: exercises.map(exid => ObjectID(exid)) }}).toArray()

This query returns every exercise I need but in the wrong order and without duplicates.

Can I achieve such a result in one query using MongoDB? I know that I can do something like that (didn't test it, just as an example):

exercises.map(exid => db.collection("exercises").find({id: ObjectID(exid)});

Something like this should give me the array I need, but I guess this is not the right way to do it, making a separate query to get a specific exercise.

P.S. I know that I can store exercises in a document itself, not using the external exercises collection for that, but the thing is, some programs may refer to the same exercise, that's why I think I need an external collection for this.


Solution

  • I decided to get a query of all exercises from server, then map all of my IDs to values from this array from server. Like that:

    db.collection("exercises")
      .find({_id: {$in: g.exercises.map(exid => ObjectID(exid)) }})
      .toArray()
      .then(res => g.exercises.map(exid => res.find(exs => exs._id == exid)))
    

    Explanation of this query:

    • get an array of all exercises with corresponding IDs from server (using MongoDB's $in operator)
    • convert it to array
    • map each element of theg.exercises array to the element of array from server (res) where ID is the same as requested

    This is 1 query to request all the data I need.

    Hope it'll help somebody.