1

I have following collections in MongoDB

Profile Collection

> db.Profile.find()
{ "_id" : ObjectId("5ec62ccb8897af3841a46d46"), "u" : "Test User", "is_del": false }

Store Collection

> db.Store.find()
{ "_id" : ObjectId("5eaa939aa709c30ff4703ffd"), "id" : "5ec62ccb8897af3841a46d46",  "a" : { "ci": "Test City", "st": "Test State" }, "ip" : false }, "op" : [ ], "b" : [ "normal" ], "is_del": false}

Item Collection

> db.Item.find()
{ "_id" : ObjectId("5ea98a25f1246b53a46b9e10"), "sid" : "5eaa939aa709c30ff4703ffd", "n" : "sample", "is_del": false}

Relation among these collections are defined as follows:

  1. Profile -> Store: It is 1:n relation. id field in Store relates with _id field in Profile.
  2. Store -> Item: It is also 1:n relation. sid field in Item relates with _id field in Store.

Now, I need to write a query to find the all the store of profiles alongwith their count of Item for each store. Document with is_del as true must be excluded.

I am trying it following way:

  1. Query 1 to find the count of item for each store.
  2. Query 2 to find the store for each profile.

Then in the application logic use both the result to produce the combined output.

I have query 1 as follows:

db.Item.aggregate({$group: {_id: "$sid", count:{$sum:1}}})

Query 2 is as follows:

db.Profile.aggregate([{ "$addFields": { "pid": { "$toString": "$_id" }}},   { "$lookup": {"from": "Store","localField": "pid","foreignField": "id",  "as": "stores"}}])

In the query, is_del is also missing. Is there any simpler way to perform all these in a single query? If so, what will be scalability impact?

4
  • 1
    The structure of your documents in Store collection is a bit strange, is there supposed to be a closing curly bracket after "ip": false ? Commented Jul 27, 2020 at 4:55
  • Why don't you post some sample data of all collections? Commented Jul 27, 2020 at 5:00
  • @thammada.ts Thanks for pointing out. I think Ashh corrected this. Commented Jul 27, 2020 at 6:17
  • @varman: Sample data is there. If you need more info, let me know. Commented Jul 27, 2020 at 6:17

1 Answer 1

2

You can use uncorrelated sub-queries, available from MongoDB v3.6

db.Profile.aggregate([
  {
    $match: { is_del: false }
  },
  {
    $lookup: {
      from: "Store",
      as: "stores",
      let: {
        pid: { $toString: "$_id" }
      },
      pipeline: [
        {
          $match: {
            is_del: false,
            $expr: { $eq: ["$$pid", "$id"] }
          }
        },
        {
          $lookup: {
            from: "Item",
            as: "items",
            let: {
              sid: { $toString: "$_id" }
            },
            pipeline: [
              {
                $match: {
                  is_del: false,
                  $expr: { $eq: ["$$sid", "$sid"] }
                }
              },
              {
                $count: "count"
              }
            ]
          }
        },
        {
          $unwind: "$items"
        }
      ]
    }
  }
])

Mongo Playground

To improve performance, I suggest you store the reference ids as ObjectId so you don't have to convert them in each step.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.