简体   繁体   中英

How to lookup a field in an array of subdocuments in mongoose?

I have an array of review objects like this:

   "reviews": {
        "author": "5e9167c5303a530023bcae42",
        "rate": 5,
        "spoiler": false,
        "content": "This is a comment This is a comment This is a comment.",
        "createdAt": "2020-04-12T16:08:34.966Z",
        "updatedAt": "2020-04-12T16:08:34.966Z"
    },

What I want to achieve is to lookup the author field and get the user data, but the problem is that the lookup I am trying to use only returns this to me:

Code:

 .lookup({
    from: 'users',
    localField: 'reviews.author',
    foreignField: '_id',
    as: 'reviews.author',
  })

Response:

api的响应

Any way to get the author's data in that field? That's where the author's Id is.

Try to execute below query on your database:

db.reviews.aggregate([
  /** unwind in general is not needed for `$lookup` for if you wanted to match lookup result with specific elem in array is needed */
  {
    $unwind: { path: "$reviews", preserveNullAndEmptyArrays: true },
  },
  {
    $lookup: {
      from: "users",
      localField: "reviews.author",
      foreignField: "_id",
      as: "author", // Pull lookup result into 'author' field
    },
  },
  /** Update 'reviews.author' field in 'reviews' object by checking if   'author' field got a match from 'users' collection.
   * If Yes - As lookup returns an array get first elem & assign(As there will be only one element returned -uniques),
   * If No - keep 'reviews.author' as is */
  {
    $addFields: {
      "reviews.author": {
        $cond: [
          { $ne: ["$author", []] },
          { $arrayElemAt: ["$author", 0] },
          "$reviews.author",
        ],
      },
    },
  },
  /** Group back the documents based on '_id' field & push back all individual 'reviews' objects to 'reviews' array */
  {
    $group: {
      _id: "$_id",
      reviews: { $push: "$reviews" },
    },
  },
]);

Test: MongoDB-Playground

Note: Just in case if you've other fields in document along with reviews that needs to be preserved in output then starting at $group use these stages:

  {
    $group: {
      _id: "$_id",
      data: {
        $first: "$$ROOT"
      },
      reviews: {
        $push: "$reviews"
      }
    }
  },
  {
    $addFields: {
      "data.reviews": "$reviews"
    }
  },
  {
    $project: {
      "data.author": 0
    }
  },
  {
    $replaceRoot: {
      newRoot: "$data"
    }
  }

Test: MongoDB-Playground

Note: Try to keep queries to run on lesser datasets maybe by adding $match as first stage to filter documents & also have proper indexes.

you should use populate('author') method of mongoose on the request to the server which gets the id of that author and adds the user data to the response of mongoose and dont forget to set your schema in a way that these two collections are connected in your review schema you should add ref to the schema which the author user is saved author: { type: Schema.Types.ObjectId, ref: 'users' },

You can follow this code

$lookup:{
            from:'users',
            localField:'reviews.author',
            foreignField:'_id',
            as:'reviews.author'
        }
**OR**

> When You find the doc then use populate
> reviews.find().populate("author")


The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM