1

I have the following collection:

{
 _id: 1,
 docs: [{
          name: file1,
          labels: [label1, label2, label3, label4]
        },{
          name: file2,
          labels: [label3, label4]
        },{
          name: file3,
          labels: [label1, label3, label4]
        }]
 }

When a user searches for labels, I need to get all the docs that have those labels.

So if a user searches for "label1" and "label3", I need to get "file1" and "file3". At the moment I have the following code:

    var collection = db.collection(req.user.username);

    collection.aggregate([
      // Unwind each array
      { "$unwind": "$docs" },
      { "$unwind": "$docs.labels" },

      // Filter just the matching elements
      {
          "$match": {
              "docs.labels": { "$all": ["label1", "label3"] }
          }
      }
    ]).toArray(function (err, items) {
        res.send(items);
    });

This works fine if I only search for "label1" or "label3", but not the two together. Can you please help me with this, since I haven't found an answer that works myself.

3
  • 1
    What is your mongod version? Commented Jan 2, 2017 at 20:00
  • Why you didn't use mongoose module? Commented Jan 2, 2017 at 20:03
  • @Styvane my mongo is version 3.2.10 Commented Jan 2, 2017 at 20:04

1 Answer 1

1

You can efficiently do this by $filtering your documents in the $project stage.

let inputLabels = ["label1", "label3"];

collection.aggregate([
    { "$match": { "docs.labels": { "$all": inputLabels }}}, 
    { "$project": { 
        "docs": { 
            "$filter": { 
                "input": "$docs", 
                "as": "doc", 
                "cond": { "$setIsSubset": [ inputLabels, "$$doc.labels" ] }
            }
        }
    }}
])]).toArray(function (err, items) {
        res.send(items);
    });
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you very much!! I tried using $project and $filter myself, but I wasn't able to get the desired result as I didn't fully understand it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.