mongodb 2级聚合查找

时间:2018-11-03 08:50:00

标签: mongodb aggregation-framework

我有那些收集模式

Schema.users = {
    name : "string",
    username : "string",
    [...]
}

Schema.rooms = {
    name : "string",
    hidden: "boolean",
    user: "string",
    sqmt: "number",
    service: "string"
}

Schema.room_price = {
    morning : "string",
    afternoon: "string",
    day: "string",
    room:'string'
}

我需要将用户与房间汇总在一起,并为每个房间汇总特定的房间价格。

预期结果将是

[{
_id:"xXXXXX",
name:"xyz",
username:"xyz",
rooms:[
  {
    _id: 1111,
    name:'room1',
    sqmt: '123x', 
    service:'ppp',
    room_prices: [{morning: 123, afternoon: 321}]
  }
]}]

聚合的第一部分可能是

db.collection('users').aggregate([
  {$match: cond},
  {$lookup: {
    from: 'rooms',
    let: {"user_id", "$_id"},
    pipeline: [{$match:{expr: {$eq: ["$user", "$$user_id"]}}}],
    as: "rooms"
  }}])

但是我不知道如何在同一总数内获得房价

1 个答案:

答案 0 :(得分:3)

假设String.Format集合中的room具有room_prices集合中name的匹配数据,则该表达式将匹配“内部” $lookup表达式与另一个$lookup的管道:

rooms

这还会在其中添加$project,以便仅从价格中选择所需的字段。使用$lookup的表达形式时,实际上确实可以表达“管道”,它可以是任何聚合管道组合。这样可以进行复杂的操作和类似的“嵌套查询”。

请注意,使用猫鼬还可以使用以下方法从模型对象获取集合名称:

  db.collection('users').aggregate([
    { $match: cond },
    { $lookup: {
      from: 'rooms',
      let: { "user_id": "$_id" },
      pipeline: [
       { $match:{ $expr: { $eq: ["$user", "$$user_id"] } } },
       { $lookup: {
         from: 'room_prices',
         let: { 'name': '$name' },
         pipeline: [
           { $match: { $expr: { $eq: [ '$room', '$$name' } } },
           { $project: { _id: 0, morning: 1, afternoon: 1 } }
         ],
         as: 'room_prices'
       }}
      ],
      as: "rooms"
    }}
  ])

这通常是将来的证明,以防止可能的模型配置更改,这些更改可能会更改基础集合的名称。


在MongoDB 3.6及更高版本提供的子管道语法之前,您也可以使用 from: RoomPrice.collection.name 的“旧式”形式进行几乎相同的操作。只是更多的处理和重构:

$lookup

主要是使用$unwind会带来更多开销,并且还要注意,“字段选择”实际上意味着您确实从 db.collection('users').aggregate([ { $match: cond }, // in legacy form { $lookup: { from: 'rooms', localField: 'user_id', foreignField: 'user', as: 'rooms' }}, // unwind the output array { $unwind: '$rooms' }, // lookup for the second collection { $lookup: { from: 'room_prices', localField: 'name', foreignField: 'room', as: 'rooms.room_prices' }}, // Select array fields with $map { $addFields: { 'rooms': { 'room_prices': { $map: { input: '$rooms.room_prices', in: { morning: '$this.morning', afternoon: '$this.afternoon' } } } } }}, // now group back to 'users' data { $group: { _id: '$_id', name: { $first: '$name' }, username: { $first: '$username' }, // same for any other fields, then $push 'rooms' rooms: { $push: '$rooms' } }} ]) 返回了“整个文档” “第一” < / em>,只有在完成后才能选择字段。

因此,较新的语法有很多优点,但是如果您愿意,也可以使用较早的版本。