MongoDB retrieve every document contained in another document's array

147 Views Asked by At

I'm new to MongoDB so this might be a basic question but I am having trouble in how to approach it.

I want to find one document in my collection, like so:

db.collection("articles").find({curid:"1000143"}).asArray();

One of the fields returned is an array containing other document's 'curid' (a unique value):

HDP_Topics = ["1124516", "101388", "1031462", "1053284", "1077080", "1150760", "1092377", "1100194", "1103692", "1135134", "1134909", "1119820", "1000634", "1120316", "1000143"]

What I want to do is to find each of these other documents and append them onto the already existing find query results. I'm sure there must be a way without having make a new search for every element in the array.

(I'm using mongoDB Atlas's Stitch if that makes any difference)

2

There are 2 best solutions below

4
On

If I understand the question correctly, you want to use the HDP_Topics field to trigger a new search. You can use a $graphLookup for this:

db.articles.aggregate( [
   {
      $graphLookup: {
         from: "articles",
         startWith: "1000143",
         connectFromField: "HDP_Topics",
         connectToField: "curid",
         as: "otherDocs",
         maxDepth: 2
      }
   }
] )

If you want to have more recursion level, change maxDepth. This search will put the resulting documents under otherDocs.

0
On

It ain't pretty, but I couldn't see any other alternative. So this is what I did in the end for a quick fix. Hopefully the aggregation functions (thanks @enys) will be implemented soon.

function getDataByTitle(title){
    try{
      var deferred = $q.defer();
      var docs = db.collection("articles").find({title:title}).asArray().then(
        docs => {
          var newData = [[docs[0]]];
          var docsLength = $rootScope.articlesToCompare;
          for(let i=1, p = Promise.resolve(); i < docsLength; i++){
            p = p.then(_ => new Promise(resolve => {
                newData.push(db.collection("articles").find({curid:docs[0].cosineArray[i]}).asArray());
                resolve();
                if(i==docsLength-1) deferred.resolve(newData);
            }));
          }
        }
      );
      return deferred.promise;
    } catch(err) {
      console.log(err);
    }
 }

Note: I changed from 'HDP_Topics' to 'cosineArray'. Also docsLength is predefined, which just works as a $limit alternative, seeing as I'm using multiple queries I can't defined this in the query itself.

The result is an array of arrays of articles. You can see it in action here: unitroll.me , using the search bar on the top-right.