Search code examples
mongodbmongoosemongoose-schema

Find by _id on an array of objects in mongodb database


I'm trying to find the id of an object inside an array of objects. That _id has the same field name _id as others in the document. This is my model (brief)

var CardSchema = new mongoose.Schema({
  beName: String,
  beLink: String,
  cards: [{ 
    cardType: String,
    cardBundle: String
  }]

This is an sample of my database content

_id: ObjectId(5a52540638086448bf4235e8)
beName: Name1
beLink: Link1
cards: Array
 0: Object
    cardType: type1
    cardBundle: 1
    _id: ObjectId(5a526749d0ddab4bcdcc1556)
 1: Object
    cardType: type2
    cardBundle: 1
    _id: ObjectId(5a526749d0ddab4bcdcc1557)

...

_id: ObjectId(5a52540638086448bf4235e9)
beName: Namex
beLink: Linkx
cards: Array
 0: Object
    cardType: typex
    cardBundle: x
    _id: ObjectId(5a526749d0ddab4bcdcc1598)
 1: Object
    cardType: type2
    cardBundle: 1
    _id: ObjectId(5a526749d0ddab4bcdcc1599)

I'm trying to find the id of an specific card like this

Cards.find({ _id: req.params.id}, function (err, post) {
    if (err) return next(err);
    res.json(post);
  });

But I get an empty result

I also tried

Cards.find({ _id: new ObjectId(req.params.id)}...

Solution

  • You probably need to use an aggregate function to $unwind the array of cards to find the matching card based on _id.

    so, in mongoose instead of find use aggregate pipeline

    sample doc

    > db.cards.findOne()
    {
        "_id" : ObjectId("5a52f4136fe82b42b7439a21"),
        "beName" : "Name1",
        "beLink" : "Link1",
        "cards" : [
            {
                "cardType" : "type1",
                "cardBundle" : 1,
                "_id" : "5a52f3a66f112b42b7439a20"
            },
            {
                "cardType" : "type2",
                "cardBundle" : 1,
                "_id" : "5a52f3a66f112b42b7439a21"
            }
        ]
    }
    

    aggregate function

    > db.cards.aggregate([{$unwind: "$cards"}, {$match:{"cards._id" : "5a52f3a66f112b42b7439a20"}}] )
    

    result doc

    > db.cards.aggregate([{$unwind: "$cards"}, {$match:{"cards._id" : "5a52f3a66f112b42b7439a20"}}] ).pretty()
    {
        "_id" : ObjectId("5a52f4136fe82b42b7439a21"),
        "beName" : "Name1",
        "beLink" : "Link1",
        "cards" : {
            "cardType" : "type1",
            "cardBundle" : 1,
            "_id" : "5a52f3a66f112b42b7439a20"
        }
    }
    > 
    

    You can optimise it further if you know the parent _id, in the aggregate pipeline $match by parent _id, then $unwind, then $match on array card _id

    > db.cards.aggregate([{$match:{"_id":ObjectId("5a52f4136fe82b42b7439a21")}},{$unwind: "$cards"}, {$match:{"cards._id" : "5a52f3a66f112b42b7439a20"}}] )