Akash Kumar Verma
Akash Kumar Verma

Reputation: 3318

lookup with condition in mongoose

I have two collections. articles and bookmarks.

articles

{
    _id: "5faa889ade5e0a6326a873d3",
    name: "article 1"
},
{
    _id: "5faa889ade5e0a6326a873d",
    name: "article 2"
}

bookmarks

{
    _id: "5faa889ade5e0a6326a873d1",
    user_id: "5fc7b50da483a66a86aa7e9e",
    model_id: "5faa889ade5e0a6326a873d3"
}

I want to join article with bookmark. if user bookmarked a article. what i have tried

const aggregate = await Articles.aggregate([{
        $lookup: {
            from: "categories",  
            localField: "category_id",
            foreignField: "_id",
            as: "category_id"
        }
    },
    {

        $lookup: {
            from: "bookmarks",  
            localField: "_id",
            foreignField: "model_id",
            as: "bookmarks"
        }
    }
]);

but it will gives all bookmark for the article not only logged in user bookmark. so how can I add a condition.

{ "user_id": objectId(req.user._id) } // logged user id

Upvotes: 2

Views: 3979

Answers (2)

turivishal
turivishal

Reputation: 36094

You can use $lookup with pipeline starting from MongoDB v3.6,

  • let to pass localField _id as model_id variable, you can use the field inside lookup pipeline using $$ reference,
  • pipeline to put $match stage and match your required conditions and user_id condition
  {
    $lookup: {
      from: "bookmarks",
      let: { model_id: "$_id" },
      pipeline: [
        {
          $match: {
            $expr: { $eq: ["$$model_id", "$model_id"] },
            user_id: objectId(req.user._id)
          }
        }
      ],
      as: "bookmarks"
    }
  }

Other option for MongoDB v3.4,

  • $filter to iterate loop of bookmarks and get filtered bookmarks on the base of condition
  {
    $lookup: {
      from: "bookmarks",
      localField: "_id",
      foreignField: "model_id",
      as: "bookmarks"
    }
  },
  {
    $addFields: {
      bookmarks: {
        $filter: {
          input: "$bookmarks",
          cond: { $eq: ["$$this.user_id", objectId(req.user._id)] }
        }
      }
    }
  }

Upvotes: 3

Ramesh Reddy
Ramesh Reddy

Reputation: 10652

You can have nested pipeline inside $lookup,

db.articles.aggregate([
  {
    $lookup: {
      from: "bookmarks",
      let: {
        article_id: "$_id"
      },
      pipeline: [
        {
          $match: {
            $expr: {
              $and: [
                {
                  $eq: [
                    "$model_id",
                    "$$article_id"
                  ]
                },
                {
                  $eq: [
                    "$user_id",
                    "5fc7b50da483a66a86aa7e9a"
                  ]
                }
              ]
            }
          }
        }
      ],
      as: "bookmarks"
    }
  }
])

Here's a working playground

Upvotes: 1

Related Questions