user8725007
user8725007

Reputation: 83

MongoDB match before lookup from

I currently have three collections: artists, albums and users. Every user has a list of albums he "likes" and I'm simply trying to set up a query (or an aggregation pipeline) that would return a boolean value whether a particular user likes an album. The collections look like so:

Artists

{
        "_id" : ObjectId("5e2b5c922e1843a8ed16df3b"),
        "name" : "Death Grips",
        "formed" : "21 Dec 2010",
        "members" : [
                "Stefan Burnett",
                "Zach Hill",
                "Andy Morin"
        ],
        "based_in" : "Sacramento, CS, United States",
        "genres" : [
                "Experimental Hip Hop",
                "Industrial Hip Hop",
                "Abstract Hip Hop",
                "Hardcore Hip Hop",
                "Glitch Hop",
                "Noise Rock"
        ]
}

Albums

{
    "_id" : ObjectId("5e2c41a4dce5f62fb2488ed8"),
    "artist" : ObjectId("5e2b5c922e1843a8ed16df3b"),
    "title" : "The Money Store",
    "release_date" : "24 April 2012",
    "image" : "5e2b9fd5b9be486f427f8331.jpg",
    "rating" : 3.96,
    "genres" : [
            "Experimental Hip Hop",
            "Industrial Hip Hop",
            "Abstract Hip Hop",
            "Hardcore Hip Hop",
            "Glitch Hop",
            "Noise Rock"
    ],
    "descriptors" : [
            "aggressive",
            "angry",
            "energetic",
            "manic",
            "noisy",
            "nihilistic"
    ],
    "lang" : "English",
    "track_listing" : [
            "Get Got",
            "The Fever",
            "Lost Boys",
            "Black Jack",
            "Hustle Bones",
            "I've Seen Footage",
            "Double Helix",
            "System Blower",
            "The Cage",
            "Punk Weight",
            "Fuck That",
            "Bitch Please",
            "Hacker"
    ]
}

Users

{
        "_id" : ObjectId("5e2c610157053b19fb28ee4e"),
        "username" : "stackoverflow_user",
        "liked_albums" : [
                "5e2c41a4dce5f62fb2488ed8"
        ]
}

And this is what I'm trying to do:

albums = col.aggregate([
    {
        "$lookup":{
            "from": "artists",
            "localField": "artist",
            "foreignField": "_id",
            "as": "artist"
        }
    }, ...something that would return true
       if the a user with a particular id
       likes that album.

This is the approximate return query I want to achieve with the user ObjectId("5e2c610157053b19fb28ee4e"):

{
    "_id" : ObjectId("5e2c41a4dce5f62fb2488ed8"),
    "artist" : {
        "_id" : ObjectId("5e2b5c922e1843a8ed16df3b"),
        "name" : "Death Grips",
        "formed" : "21 Dec 2010",
        "members" : [
                "Stefan Burnett",
                "Zach Hill",
                "Andy Morin"
        ],
        "based_in" : "Sacramento, CS, United States",
        "genres" : [
                "Experimental Hip Hop",
                "Industrial Hip Hop",
                "Abstract Hip Hop",
                "Hardcore Hip Hop",
                "Glitch Hop",
                "Noise Rock"
        ]
    },
    "title" : "The Money Store",
    "release_date" : "24 April 2012",
    "image" : "5e2b9fd5b9be486f427f8331.jpg",
    "rating" : 3.96,
    "genres" : [
            "Experimental Hip Hop",
            "Industrial Hip Hop",
            "Abstract Hip Hop",
            "Hardcore Hip Hop",
            "Glitch Hop",
            "Noise Rock"
    ],
    "descriptors" : [
            "aggressive",
            "angry",
            "energetic",
            "manic",
            "noisy",
            "nihilistic"
    ],
    "lang" : "English",
    "track_listing" : [
            "Get Got",
            "The Fever",
            "Lost Boys",
            "Black Jack",
            "Hustle Bones",
            "I've Seen Footage",
            "Double Helix",
            "System Blower",
            "The Cage",
            "Punk Weight",
            "Fuck That",
            "Bitch Please",
            "Hacker"
    ],
    "liked": true
}

Thanks!

Upvotes: 0

Views: 306

Answers (1)

Valijon
Valijon

Reputation: 13103

Does this solution meet your requirements?

In the last stage, we iterate all users who likes the album. Change $filter condition to filter user _id.

db.albums.aggregate([
  {
    "$lookup": {
      "from": "artists",
      "localField": "artist",
      "foreignField": "_id",
      "as": "artist"
    }
  },
  {
    "$lookup": {
      "from": "users",
      "let": {
        album_id: {
          $toString: "$_id"
        }
      },
      "pipeline": [
        {
          $match: {
            $expr: {
              $in: [
                "$$album_id",
                "$liked_albums"
              ]
            }
          }
        }
      ],
      "as": "users"
    }
  },
  {
    $addFields: {
      liked: {
        $toBool: {
          $size: {
            $filter: {
              input: "$users",
              cond: {
                $eq: [
                  "$$this._id",
                  ObjectId("5e2c610157053b19fb28ee4e")
                ]
              }
            }
          }
        }
      }
    }
  },
  {
    $unset: "users"
  }
])

MongoPlayground

Upvotes: 2

Related Questions