简体   繁体   中英

Query in nested document in mongodb

Here is my mongoose schema:

const chapterSchema = mongoose.Schema({
title: {
    type: String
},
number: {
    type: Number
}
})

const bookSchema = mongoose.Schema({
    title: {
        type: String
    },
    author: {
        type: String
    },
    chapters: [chapterSchema]
})

const Book = mongoose.model('Book', bookSchema)
module.exports = Book

Here is my database:

{
"_id": "5f56f8e66a7eee227c1acc0a",
"title": "Book1",
"author": "Author1",
"chapters": [{
    "_id": "5f56fa47a78fbf03cc32d16d",
    "title": "Chapter1",
    "number": 1
}, {
    "_id": "5f56fad10820300de031317f",
    "title": "Chapter2",
    "number": 2,
}]
}

I want to find a specific chapter from the chapters array by it's id. So, I wrote this code:

router.get('/:id', async function (req, res) {
try {
    const id = req.params.id
    await Book.findById(id, function (err, chapter) {
        res.render('chapter.hbs', {
            chapter: chapter
        })
    })
} catch (error) {
    res.redirect('/')
}
})

According to the chapter id, I want this result:

{
    "_id": "5f56fa47a78fbf03cc32d16d",
    "title": "Chapter1",
    "number": 1
}

or

{
    "_id": "5f56fad10820300de031317f",
    "title": "Chapter2",
    "number": 2,
}

What should I do to find a specific chapter using it's id?

You are searching on Book using findById of chapters Id, it will not give result since it is not Book Id,

You will need to use $elemMatch for this

check this Querying for Object in Mongoose Sub Array for reference

You can do this using the aggregate function.

router.get('/:id', async function (req, res) {
  try {
    const id = req.params.id
    await Books.aggregate([
      {
        $project: {
          title: 1,
          author: 1,
          chapters: {
            $filter: {
              input: "$chapters",
              as: "chapter",
              cond: {
                $eq: [
                  "$$chapter.id", id
                ]
              }
            }
          }
        }
      }
    ])
  } catch (error) {
    res.redirect('/')
  }
})

You can use aggregate() function,

  • $match your condition
  • $filter to get specific chapter id
  • $replaceWith to replace chapter in root
const id = mongoose.Types.ObjectId(req.params.id);

let chapter = await Book.aggregate([
  { $match: { "chapters._id": id } },
  {
    $replaceWith: {
      $arrayElemAt: [
        {
          $filter: {
            input: "$chapters",
            cond: { $eq: ["$$this._id", id] }
          }
        },
        0
      ]
    }
  }
]);

console.log(chapter);

Playground

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM