0

I have this mongoose model:

var mySubEntitySchema = new Schema({
  property1: String,
  property2: String
});

var myEntitySchema = new Schema({
  name: String,
  sub: [mySubEntitySchema]
});

export var MyEntityModel: mongoose.Model<MyEntityDocument> = mongoose.model<MyEntityDocument>("MyEntity", myEntitySchema);

Now I want to get a specific MyEntityDocument for which I have the _id, but only with the subDocuments matching property1 = "example".

Is there any way to do that?

I tried a solution using Aggregate but without any success:

MyEntityModel.aggregate([
{$match: { "_id": myId, "sub.property1":"example" }},
      {$unwind: "$sub"},
      {$match: { "sub.property1":"example"}},
      {$group: {"_id":"$_id","subs":{$push:"$sub"}}}
    ], (error, result) => {
        console.log("Result = " + JSON.stringify(result));
      }
    });

But it returns nothing. If I don't put "_id": myId in the first $match clause, then I get results, but I only want the one result that corresponds to the _id I have.

Anyone knows how I can do this?

EDIT: As asked, here is an example.

With this data:

  {
    "_id": "54c12276fcb2488d300795e4",
    "name": "a",
    "sub": [
      {
        "_id": "54c12276fcb2488d300795e0",
        "property1": "example",
        "property2": "something"
      },
      {
        "_id": "54c12276fcb2488d300795e1",
        "property1": "notmuch",
        "property2": "somethingelse"
      },
      {
        "_id": "54c12276fcb2488d300795e2",
        "property1": "notinteresting",
        "property2": "something"
      },
      {
        "_id": "54c12276fcb2488d300795e3",
        "property1": "example",
        "property2": "anotherthing"
      }
    ]
  },
  {
    "_id": "54c12277fcb2488d300795e5",
    "name": "b",
    "sub": [
      {
        "_id": "54c12276fcb2488d300795e6",
        "property1": "example",
        "property2": "word"
      }
    ]
  }

I want the entity with _id "54c12276fcb2488d300795e4" and the subdocs that match property1 = "example". So the expected result is:

  {
    "_id": "54c12276fcb2488d300795e4",
    "name": "a",
    "sub": [
      {
        "_id": "54c12276fcb2488d300795e0",
        "property1": "example",
        "property2": "something"
      },
      {
        "_id": "54c12276fcb2488d300795e3",
        "property1": "example",
        "property2": "anotherthing"
      }
    ]
  }

2 Answers2

0

You can use findOne to retrieve what you want.

MyEntityModel.findOne({_id : myId , "sub.property1" :"example"},{'sub.$' : 1},function(err,result){
    if(!err)
    {
        if(result)
        {
            //result is the document you were searching for
        }
    }
});

{'sub.$' : 1} will return only the matched element.

Go through mongoose query documentation for better understanding.

Ravi Shankar Bharti
  • 8,922
  • 5
  • 28
  • 52
0

Your query seems to be working fine and as expected to get the result, except the syntax of the aggregate function is improper. Refer this link on how aggregate queries are written using mongoose. You shouldn't be passing an array as you would in mongodb console. Just pass the queries separated by commas as shown in the query below.

MyEntityModel.aggregate(
  {$match: { "_id": myId, "sub.property1":"example" }},
  {$unwind: "$sub"},
  {$match: { "sub.property1":"example"}},
  {$group: {"_id":"$_id","name": {"$first": "$name"}, "subs":{$push:"$sub"}}}
, (error, result) => {
    console.log("Result = " + JSON.stringify(result));
  }
});
Ananth Pai
  • 1,939
  • 14
  • 15
  • Still doesn't work for me, I have no idea why. If I don't put the match on _id it just works fine, but as soon as I add this criteria, the result is empty. Well in my real code I don't exactly match on _id but on another property, don't know if it makes things different? – Camille Blanc Sep 22 '16 at 20:06
  • can you share the value of `myId` before its passed to the aggregate function, in a `console.log` – Ananth Pai Sep 23 '16 at 07:52
  • I simplified my code so that it would be easier to understand, so I don't really have a myId value. But anyway my criteria is good, because things go like that: A findOne with "_id": myId gives back a result. The aggregate without "_id": myId gives back all documents with the subdocuments matching sub.property1: "example" (and only those subdocuments) As soon as I add the "_id": myId to the aggregate, I suddenly get no result. – Camille Blanc Sep 24 '16 at 13:10