Search code examples
mongodbmongoosemongodb-querymongoose-populate

MongoDB/Mongoose One-to-Many with refence to parent in child - group and join


I followed the suggestion in Mongo docs to have Parent & Child collections with reference to parent in the child collection as the child collection has the prospect to grow. https://docs.mongodb.com/manual/tutorial/model-referenced-one-to-many-relationships-between-documents/

Publisher(Parent) Collection:

{
   _id: "oreilly",
   name: "O'Reilly Media",
   founded: 1980,
   location: "CA"
}

Books(Child) Collection - with reference to publisher in them:

{
   _id: 123456789,
   title: "MongoDB: The Definitive Guide",
   author: [ "Kristina Chodorow", "Mike Dirolf" ],
   published_date: ISODate("2010-09-24"),
   pages: 216,
   language: "English",
   publisher_id: "oreilly"
},{
   _id: 234567890,
   title: "50 Tips and Tricks for MongoDB Developer",
   author: "Kristina Chodorow",
   published_date: ISODate("2011-05-06"),
   pages: 68,
   language: "English",
   publisher_id: "oreilly"
}

Now what I am trying to achieve is get all publishers with a sub-array of books by them:

    {
  "_id": "oreilly",
  "name": "O'Reilly Media",
  "founded": 1980,
  "location": "CA",
  "books": [
    {
      "_id": 123456789,
      "title": "MongoDB: The Definitive Guide",
      "author": [
        "Kristina Chodorow",
        "Mike Dirolf"
      ],
      "published_date": "2010-09-24",
      "pages": 216,
      "language": "English",
      "publisher_id": "oreilly"
    },
    {
      "_id": 234567890,
      "title": "50 Tips and Tricks for MongoDB Developer",
      "author": "Kristina Chodorow",
      "published_date": "2011-05-06",
      "pages": 68,
      "language": "English",
      "publisher_id": "oreilly"
    }
  ]
}

I use Mongoose, & I know I could've done .populate("books") if I had stored an array of book references in the publisher - which I do not want to do since books will keep increasing. I would like to know how to achieve the same result with publisher reference being present in the books collection.


Solution

  • You must use $lookup to perform a join.

    db.publisher.aggregate([{$lookup: {from: 'books', localField: '_id', foreignField: 'publisher_id', as: 'books'}} ]).pretty()
    {
            "_id" : "oreilly",
            "name" : "O'Reilly Media",
            "founded" : 1980,
            "location" : "CA",
            "books" : [
                    {
                            "_id" : 123456789,
                            "title" : "MongoDB: The Definitive Guide",
                            "author" : [
                                    "Kristina Chodorow",
                                    "Mike Dirolf"
                            ],
                            "published_date" : ISODate("2010-09-24T00:00:00Z"),
                            "pages" : 216,
                            "language" : "English",
                            "publisher_id" : "oreilly"
                    },
                    {
                            "_id" : 234567890,
                            "title" : "50 Tips and Tricks for MongoDB Developer",
                            "author" : "Kristina Chodorow",
                            "published_date" : ISODate("2011-05-06T00:00:00Z"),
                            "pages" : 68,
                            "language" : "English",
                            "publisher_id" : "oreilly"
                    }
            ]
    }