【问题标题】:Mongo Multiple Level Aggregate Lookup GroupMongo 多级聚合查找组
【发布时间】:2020-08-26 23:50:17
【问题描述】:

我有 3 个集合,用户、药房和城市。我希望我的结果如下所示:

{
    _id: ,
    email: ,
    birthdate: ,
    type: ,
    dispensary: {
      _id: ,
      schedule: ,
      name: ,
      address: ,
      phone: ,
      user:,
      city: {
         name:,
        },
    },
  }

但是,我在第一层将城市对象取出,并且我希望将其作为药房集合的子对象。

这是我目前正在使用的管道:

    User.aggregate
              ([
                {
                  $match: { "_id": id } 
                },
                {
                  $lookup:
                  {
                    from: Dispensary.collection.name,
                    localField: "dispensary",
                    foreignField: "_id",
                    as: "dispensary"
                  },
                },
                {"$unwind": {path:"$dispensary",preserveNullAndEmptyArrays: true} ,},
                {
                  $lookup:
                  {
                    from: City.collection.name,
                    localField: "dispensary.city",
                    foreignField: "_id",
                    as: "city"
                  },
                },
                {"$unwind": {path:"$city",preserveNullAndEmptyArrays: true}} ,
                {
                  "$group": {
                  _id: "$_id", 
                  email : { $first: '$email' },
                  birthdate : { $first: '$birthdate' },
                  type : { $first: '$type' },
                  dispensary: { $push:  "$dispensary" }, 
                  city: { $push:  "$city" }, 
                  },
                },
                {"$unwind": {path:"$dispensary",preserveNullAndEmptyArrays: true}} ,
                {"$unwind": {path:"$city",preserveNullAndEmptyArrays: true}} ,

              ], (aggErr, aggResult) => {
                (aggErr)  ? console.log(aggResult)
                          : console.log(aggResult)
              })

架构:

const CitySchema = new Schema({
    name: { type: String, required: true, unique:true },
    zip: { type: String, required: true },
});

const DispensarySchema = new Schema({
    name: { type: String, required: true },
    address: { type: String, required: true },
    longitude: { type: String, required: true },
    latitude: { type: String, required: true },
    phone: { type: String, required: true },
    user: {type: mongoose.Schema.Types.ObjectId, ref: 'User'},
    schedule: [{type: mongoose.Schema.Types.ObjectId, ref: 'Schedule'}],
    city: {type: mongoose.Schema.Types.ObjectId, ref: 'City'},
})

const UserSchema = new Schema({
    name: { type: String, required: true },
    email: { type: String, required: true, unique: true },
    password: { type:String, required: true },
    birthdate: { type: Date, required: true },
    type: { type: String, enum: ['ADMIN','DISPENSARY','CUSTOMER'], required: true},
    verificationToken: { type: String, required: false },
    resetPasswordToken: { type: String, required: false },
    resetPasswordExpires: { type: String, required: false },
    isVerified: { type: Boolean, required: true },
    isActive: { type: Boolean, required: true },
    last_session: { type: Date },
    last_ip_session: { type:String },
    dispensary: {type: mongoose.Schema.Types.ObjectId, ref: 'Dispensary'},
},
{ timestamps: true }
)

【问题讨论】:

  • 您应该附上每个集合的架构,因为这样更容易为您提供帮助。
  • 您在dispensary 的预期输出是一个对象。为什么要使用$push 来获取数组?应该是数组吗?
  • 我使用 push 将其作为药房添加到根数组中,并且我想用 city 这样做,在药房内添加 city 但我看到它不允许在一组中创建 3 个级别,我试图增加第二个小组赛阶段,但我没有达到它

标签: javascript json mongodb express mongoose


【解决方案1】:

我认为你根本不需要使用$group,你可以在第二个$lookup中使用as: "dispensary.city"

[
  {
    "$match": {
      "_id": id
    }
  },
  {
    "$lookup": {
      from: Dispensary.collection.name,
      localField: "dispensary",
      foreignField: "_id",
      as: "dispensary"
    },
  },
  {
    "$unwind": {
      path: "$dispensary",
      preserveNullAndEmptyArrays: true
    },
  },
  {
    "$lookup": {
      from: City.collection.name,
      localField: "dispensary.city",
      foreignField: "_id",
      as: "dispensary.city" // modify here
    },
  },
  {
    "$unwind": {
      path: "$dispensary.city", // modify here
      preserveNullAndEmptyArrays: true
    }
  }
]

【讨论】:

  • 我该如何放松呢?因为它是以 [Object] 的形式出现的
  • dispensary.city 应该已经是一个对象,您可能需要检查是否有任何额外的$lookups。根据我的回答,您应该只有 2 个 $lookups
  • @AnthonyMedina 你在哪里看这个? [Object] 可能已经正确,但您的客户端没有显示它
  • i.imgur.com/R7wKgLA.jpg忘了最后一张,这是正确的
  • 请检查您在路径"$dispensary.city" 处正确$unwind 作为答案的最后阶段
【解决方案2】:

您可以使用另一个lookup 方法使用pipeline,这允许您在查找函数内进行更多条件/子查询。见参考:aggregate-lookup

    User.aggregate([
  {
    $match: { "_id": id } 
  },
  {
    $lookup: {
      from: Dispensary.collection.name,
      let: {dispensaryId: "$dispensary"},
      pipeline: [
        {
          $match: {
            $expr: {
               $eq: ["$_id", "$$dispensaryId"]
            }
          }
        },
        {
          $lookup:
          {
            from: City.collection.name,
            localField: "city",
            foreignField: "_id",
            as: "city"
          },
        },
        {
          $unwind: {
            path:"$city",
            preserveNullAndEmptyArrays: true
          }
        }
      ]
      as: "dispensary",
    },
  },
  {
     $unwind: {
       path:"$dispensary",
       preserveNullAndEmptyArrays: true
    }
   },
  {
    "$group": {
      _id: : {
        _id: "$_id", 
        email :  '$email' ,
        birthdate : '$birthdate' ,
        type :  '$type' 
        dispensary: "$dispensary"
     }
    }
  }
], (aggErr, aggResult) => {
  (aggErr)  ? console.log(aggResult)
            : console.log(aggResult)
})

更新:管道注意:要在管道阶段引用变量,请使用“$$”语法。`

【讨论】:

  • dispensary: "$dispensary" dispensary: { $push: "$dispensary" }, ] 它有效,但遗憾的是,在第一次查找的管道中,药房数组为空,那是因为我正在使用推送?为什么只为我工作?
  • 哦。没看清楚,问题出在$group管道上,把_id属性里面的所有字段都加进去再试试。
  • 药房仍然是空的,在这种情况下,它在没有推送的情况下工作但空了,它似乎在第一次查找的管道中出现了问题
  • 我再次更新了上面的答案,我使用$expr 访问let 上的声明值。在此处查看管道描述docs.mongodb.com/manual/reference/operator/aggregation/lookup
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-23
  • 1970-01-01
  • 1970-01-01
  • 2019-05-06
  • 2021-10-02
  • 2016-03-20
相关资源
最近更新 更多