'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 1:[1]

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"}}] )

Solution 2:[2]

Question is a bit vague, but by looking at other answers and having the card's _id in the url, I guess you have the card _id and you want to find the parent document. if so, then you don't need an aggregate. a find query does the job:

db.cards.find({"cards._id": _id})

Solution 3:[3]

Try doing it like:

const ObjectId = require("mongodb").ObjectID,

/* some other statements */

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

For Reference: https://mongodb.github.io/node-mongodb-native/api-bson-generated/objectid.html

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3 Ajay