1

I have these collections:

lists
{_id: 1, item: "a", owner: 1}
users
{_id: 1, subs: [{_id: 1, active: "Y"},{_id: 2, active: "N"}]}
subs
{_id: 1, text: "A"}
{_id: 2, text: "B"}

I want to have a result of lists with user info and with subs info that is active.

{_id: 1, item: "a", owner: {_id: 1, subs: [{_id: {_id: 1, text: "A"}, active: "Y"}]}}

I want also to sort it based on "text" field.

I tried aggregation but failed,

db.getCollection("lists").aggregate(
[
    { 
        "$lookup" : { 
            "from" : "users", 
            "localField" : "owner", 
            "foreignField" : "_id", 
            "as" : "owner"
        }
    }, 
    { 
        "$match" : { 
            "owner.0.subs" : { 
                "$elemMatch" : { 
                    "active" : "Y"
                }
            }
        }
    }
], 
{ 
    "allowDiskUse" : false
}
);

I am also using Mongoose and failed using populate. Any way to get my result?

Here, I updated my aggregation pipeline,

[
  {
    $lookup: {
      from: "users",
      as: "owner",
      let: { owner: "$owner" },
      pipeline: [
        { $match: { $expr: { $eq: ["$$owner", "$_id"] } } },
        { $unwind: { path:"$sub", preserveNullAndEmptyArrays: false} },
        { $match: { "subs.active": "Y" } },
        {
          $lookup: {
            from: "plans",
            localField: "subs._id",
            foreignField: "_id",
            as: "subs.plans"
          }
        },
        { $unwind: { path:"$subs.plans", preserveNullAndEmptyArrays: false} },
      ]
    }
  },
  { $unwind: { path: "$owner", preserveNullAndEmptyArrays: true} },
  { '$sort': { item: 1 } },
  { '$skip': 0 },
  { '$limit': 20 } ]
1
  • You have 3 collections and only 1 lookup list->users. You need at least another lookup to add subs to the equation Commented Aug 20, 2020 at 15:27

1 Answer 1

2

You can use lookup with pipeline and nested lookup,

inside lookup pipelines are:

  • $match your owner id in users collection
  • $unwind deconstruct subs array because we need to lookup with subs collection
  • $match subs is active or not
  • $lookup with subs collection
  • $unwind deconstruct subs._id that we joined from subs collection
  • $group reconstruct subs array
  • $unwind deconstruct owner array
  • $sort by item and pagination by $skip and $limit
db.getCollection("lists").aggregate([
  {
    $lookup: {
      from: "users",
      as: "owner",
      let: { owner: "$owner" },
      pipeline: [
        { $match: { $expr: { $eq: ["$$owner", "$_id"] } } },
        { $unwind: "$subs" },
        { $match: { "subs.active": "Y" } },
        {
          $lookup: {
            from: "subs",
            localField: "subs._id",
            foreignField: "_id",
            as: "subs._id"
          }
        },
        { $unwind: "$subs._id" },
        {
          $group: {
            _id: "$_id",
            subs: {
              $push: {
                _id: "$subs._id._id",
                text: "$subs._id.text",
                active: "$subs.active"
              }
            }
          }
        }
      ]
    }
  },
  { $unwind: "$owner" },
  { $sort: { item: 1 } },
  { $skip: 0 },
  { $limit: 20 }
], { allowDiskUse: false })

Playground


Your Second Edit: there is wrong key name sub in first lookup inside first $unwind, correct this,

{ $unwind: { path:"$sub", preserveNullAndEmptyArrays: false} }

to

{ $unwind: { path:"$subs", preserveNullAndEmptyArrays: false} }

Your Working Query

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

6 Comments

Hi. Kindly check my new update, I am able to get my result but when sorting it, it is not working.
what you want exactly you want to sort by item name and pagination right? so your query is invalid check updated answer.
Do you have a way to remove details and just count those documents without skip and limit?
you mean you need total size of array?, use $size or $count
can you give example of using $count / $size? I want to count total rows return of that aggregate without skip and limit option
|

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.