我需要根据 userIds 聚合两个 collections 但无法管理它

I need to aggregate two collections based on userIds but couldn't manage it

我想汇总下面的collections(评论和帐户)但是无法正确管理它所以我需要请教你们。

当前评论Collection写在下面

{
  lawyerId: { type: mongoose.Schema.Types.ObjectId },
  reviews: [
    {
      userId: { type: mongoose.Schema.Types.ObjectId, unique: true },
      message: { type: String },
      rate: { type: Number },
      createdAt: { type: Date, default: Date.now },
    },
  ],
}

如果推荐评论Collection可以这样重构

{
  lawyerId: { type: mongoose.Schema.Types.ObjectId },
  userId: { type: mongoose.Schema.Types.ObjectId },
  message: { type: String },
  rate: { type: Number },
  createdAt: { type: Date, default: Date.now },
}

帐号Collection

  {
    _id: { type: mongoose.Schema.Types.ObjectId} 
    email: { type: String, unique: true },
    firstName: { type: String },
    lastName: { type: String },
  },

获取评论的预期结果

{
 averageRate: 3.2,
 reviews: [
 {
  firstName: 'Jack',
  lastName: 'Harden',
  message: 'I dont like it',
  rate: 2, 
  createdAt: '2020-01-01T14:58:23.330+00:00'
 },
 {
  firstName: 'Takeshi',
  lastName: 'San',
  message: 'Thats nice',
  rate: 5, 
  createdAt: '2020-03-02T10:45:10.120+00:00'
 }
],
}

您应该可以使用 aggregation.

来实现此目的

您可以查看实时 demo here,它允许您 运行 此查询。

查询:

// Assuming we are searching for an lawyerId of 3

db.review.aggregate([
  {
    $match: {
      lawyerId: 3
    }
  },
  {
    $lookup: {
      from: "account",
      localField: "userId",
      foreignField: "_id",
      as: "user"
    }
  },
  {
    $unwind: "$user"
  },
  {
    $group: {
      _id: "$lawyerId",
      averageRate: {
        $avg: "$rate"
      },
      reviews: {
        $push: {
          createdAt: "$createdAt",
          firstName: "$user.firstName",
          lastName: "$user.lastName",
          message: "$message",
          rate: "$rate"
        }
      }
    }
  },
  {                    //   *******************************************
    $project: {        //   *******************************************
      _id: 0,          //   If you comment out/remove all of these lines
      averageRate: 1,  //   then the return also contains the 'lawyerId',
      reviews: 1       //   as '_id', which I would find useful...
    }                  //   *******************************************
  }                    //   *******************************************
])

结果:

上面的查询,使用上面的数据集,产生以下结果:

[
  {
    "averageRate": 3.25,
    "reviews": [
      {
        "createdAt": ISODate("2015-02-28T00:00:00Z"),
        "firstName": "First",
        "lastName": "Uno",
        "message": "Message meh",
        "rate": 3
      },
      {
        "createdAt": ISODate("2015-02-28T00:00:00Z"),
        "firstName": "Second",
        "lastName": "Dos",
        "message": "Message blah",
        "rate": 4
      },
      {
        "createdAt": ISODate("2015-02-28T00:00:00Z"),
        "firstName": "First",
        "lastName": "Uno",
        "message": "Message foo",
        "rate": 4
      },
      {
        "createdAt": ISODate("2015-02-28T00:00:00Z"),
        "firstName": "Third",
        "lastName": "Tres",
        "message": "Message bar",
        "rate": 2
      }
    ]
  }
]

数据集:

Mongo Playground中,您可以构建具有多个集合的数据库,这解释了数据结构:

db={             // <---- Database 'db'
  "account": [   // <---- Collection 'account'
    {
      _id: 21,
      email: "first.uno@gmail.com",
      firstName: "First",
      lastName: "Uno"
    },
    {
      _id: 22,
      email: "second.dos@yahoo.com",
      firstName: "Second",
      lastName: "Dos"
    },
    {
      _id: 23,
      email: "third.tres@hotmail.com",
      firstName: "Third",
      lastName: "Tres"
    }
  ],
  "review": [    // <---- Collection 'review'
    {
      lawyerId: 3,
      userId: 21,
      message: "Message meh",
      rate: 3,
      createdAt: ISODate("2015-02-28T00:00:00Z")
    },
    {
      lawyerId: 3,
      userId: 22,
      message: "Message blah",
      rate: 4,
      createdAt: ISODate("2015-02-28T00:00:00Z")
    },
    {
      lawyerId: 3,
      userId: 21,
      message: "Message foo",
      rate: 4,
      createdAt: ISODate("2015-02-28T00:00:00Z")
    },
    {
      lawyerId: 3,
      userId: 23,
      message: "Message bar",
      rate: 2,
      createdAt: ISODate("2015-02-28T00:00:00Z")
    }
  ]
}

您可以尝试使用此管道从评论集合中获取所有评论:

db.reviews.aggregate([
  {
    $lookup: {
      from: "accounts",
      localField: "userId",
      foreignField: "_id",
      as: "user"
    }
  },
  {
    $unwind: "$user"
  },
  {
    $addFields: {
      "firstName": "$user.firstName",
      "lastName": "$user.lastName"
    }
  },
  {
    $group: {
      "_id": null,
      "average_rate": {
        $avg: "$rate"
      },
      "reviews": {
        $push: "$$ROOT"
      }
    }
  },
  {
    $unset: [
      "_id",
      "reviews._id",
      "reviews.user",
      "reviews.userId",
      "reviews.lawyerId"
    ]
  }
])

结果:

[
  {
    "average_rate": 3.5,
    "reviews": [
      {
        "createdAt": "Some Review Date",
        "firstName": "Jack",
        "lastName": "Harden",
        "message": "I dont like it",
        "rate": 2
      },
      {
        "createdAt": "Some Review Date",
        "firstName": "Takeshi",
        "lastName": "San",
        "message": "That's nice",
        "rate": 5
      }
    ]
  }
]

Demo here