skip to Main Content

I have a post model with the following structure:

const postSchema = new mongoose.Schema(
    {
        caption: { type: String, maxLength: 2000 },
        creator: { type: mongoose.Schema.Types.ObjectId, ref: "User" },
    },
    { timestamps: true }
)

The creator field references the User model which is structure like so:

const userSchema = new mongoose.Schema({
    username: {
        type: String,
        required: true,
    },
    followers: [
        {
            type: mongoose.Schema.Types.ObjectId,
            ref: "User",
        },
    ],
})

I perform the following aggregation query on the Post model in order to return certian posts, with the creator field populated. The creator field is populated, however the followers property gets returned as an array of ObjectIds however I would like to populate the followers field as well.

Current aggregation query:

let postQuery = Post.aggregate([
    {
        $lookup: {
            from: "users",
            localField: "creator",
            foreignField: "_id",
            as: "creatorDoc",
        },
    },
    {
        $match: {
            "creatorDoc.username": username,
            "creatorDoc.followers": { $nin: [req.user._id] },
        },
    },
    {
        $project: {
            _id: 1,
            caption: 1,
            "creatorDoc.username": 1,
            "creatorDoc.followers": 1,
        },
    },
    {
        $unwind: "$creatorDoc",
    },
]).then((result) => {
    console.log(result)
    res.send(result)
})

Result: (note that I want the followers field to be populated, however it returns an array of object ids:

[
  {
    "_id": "66294f6765bf3ddfc42f0a9d",
    "caption": "dedededede",
    "creatorDoc": {
      // Username displays as expected
      "username": "sam",
      // I want to populate this array 
      "followers": [
        "6626753edc14c52c550834fd"
      ]
    }
  }
]

How can I populate the followers array using this aggregation query? Thanks.

2

Answers


  1. let postQuery = Post.aggregate([
        {
            $lookup: {
                from: "users",
                localField: "creator",
                foreignField: "_id",
                as: "creatorDoc",
            },
        },
        {
            $unwind: "$creatorDoc",
        }
        {
            $match: {
                "creatorDoc.username": username,
                "creatorDoc.followers": { $nin: [req.user._id] },
            },
        },
        {
            $lookup: {
                from: "users",
                localField: "creatorDoc.followers",
                foreignField: "_id",
                as: "creatorDoc.followers",
            },
        },
        {
            $project: {
                _id: 1,
                caption: 1,
                "creatorDoc.username": 1,
                "creatorDoc.followers": 1,
            },
        },
    ]).then((result) => {
        console.log(result)
        res.send(result)
    })
    
    Login or Signup to reply.
  2. If you add a pipeline stage to your $lookup you can do another $lookup while the first one is executing. You can think of it as a nested $lookup.

    Incorporating the pipeline into your existing aggregate would look something like this:

    let postQuery = await Post.aggregate([
      {
        $lookup: {
          from: "users",
          localField: "creator",
          foreignField: "_id",
          as: "creatorDoc",
          pipeline: [
            {
              $lookup: {
                from: "users",
                localField: "followers",
                foreignField: "_id",
                as: "followers"
              }
            }
          ]
        }
      },
      {
        $match: {
          "creatorDoc.username": username,
          "creatorDoc.followers": {
            $nin: [
              req.user._id
            ]
          }
        }
      },
      {
        $project: {
          _id: 1,
          caption: 1,
          "creatorDoc.username": 1,
          "creatorDoc.followers": 1
        }
      },
      {
        $unwind: "$creatorDoc"
      }
    ]);
    

    See HERE for a working example.

    Note: when you do the $match stage you need to make sure that req.user._id is an ObjectId and not a String as you will be comparing it against other ObjectIds.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search