具有多个$ match或$ pipeline条件的Mongo $ lookup

时间:2019-05-24 20:58:58

标签: javascript node.js mongodb mongoose aggregation-framework

我有两个mongo集合,一个包含联系人(又名患者),另一个包含通知。我正在尝试返回所有活动联系人状态的结果:给定的branchId / climate_id中为true,并包括其已确认的:false通知。另外,无论联系人是否收到通知,我都希望确保联系人显示在结果中。

我需要通过branchId aka clinic_id“加入”集合,然后为每个活动联系人未确认的通知创建一个数组。

联系方式:

{
  patientId: { type: String, required: true },
  clinic_id: { type: String, required: true },
  firstName: { type: String, uppercase: true, required: true },
  lastName: { type: String, uppercase: true, required: true },
  birthDate: { type: String },
  phone: { type: String, required: true },
  status: { type: Boolean, default: true }, // true - active patient
}

通知架构:

{
  branchId: { type: String, required: true }, // aka clinic_id
  patientId: { type: String, required: true },
  type: { type: String, required: true }, // sms, chat, system
  acknowledged: { type: Boolean, default: false },
  date: { type: Date, default: Date.now }
}

汇总查询:

[
  {
    $match: { clinic_id: '2', status: { $eq: true } }
  },
  {
    $lookup: {
      from: 'notifications',
      let: { patient: '$patientId' },
      pipeline: [
        {
          $match: {
            $expr: {
              $and: [
                { $eq: ['$acknowleged', false] },
                { $eq: ['$patientId', '$$patientId'] }
              ]
            }
          }
        }
      ],
      as: 'notif'
    }
  }
]

很显然,这是为了提供最好的结果-我一直在使用它,然后在节点中过滤结果:

[ 
  { $match: { clinic_id: '2', status: { $eq: true } } },
  { "$lookup": {
    "from": "notifications",
    "let": { "patientId": "$patientId" },
    "pipeline": [
      { "$match": {
        "$expr": { "$eq": ["$branchId", "2"] },
        "acknowledged": { "$eq": false }
      }}
    ],
    "as": "notif"
  }}
]

我的问题是我要么获得了正确的正确联系人,但来自具有相同患者ID但分配给另一个branchId的患者进入了notif数组。或者根据我的尝试,我可能会得到正确的notif数组,但是最初的联系人列表将缺少条目。获得我需要的输出的最佳方法是什么?

示例输出,其中包含我期望的输出和不正确的输出的注释:

{
  patientId: 1,
  clinic_id: 100,
  firstName: 'John',
  lastName: 'Doe',
  birthDate: '2000-01-01',
  phone: '6665551212',
  status: true,
  notif: [
  {
    // This is correct
    branchId: 100, // branchId matches
    patientId: 1,  // patientId matches contacts patientId
    type: 'sms',
    acknowledged: false, // notification is unacknowledged
    date: '2019-05-18T16:18:05.480Z'
  },
  {
   // This is not correct
    branchId: 200, // branchId does not match contacts branchId
    patientId: 1,
    type: 'sms',
    acknowledged: true, // only want acknowledged: false
    date: '2019-05-20T16:18:05.480Z'
  },
  {
   // This is not correct
    branchId: 100, 
    patientId: 2, // PatientId does not match contact
    type: 'sms', 
    acknowledged: false,
    date: '2019-05-20T16:18:05.480Z'
  }
  ]
}

1 个答案:

答案 0 :(得分:2)

您需要使用clinicId添加一个条件。像这样

[
  { "$match": { "clinic_id": "2", "status": { "$eq": true }}},
  { "$lookup": {
    "from": "notifications",
    "let": { "patient": "$patientId", "clinic_id": "$clinic_id" },
    "pipeline": [
      { "$match": {
        "$expr": {
          "$and": [
            { "$eq": ["$patientId", "$$patientId"] },
            { "$eq": ["$branchId", "$$clinic_id"] }
          ]
        },
        "acknowleged": false
      }}
    ],
    "as": "notif"
  }}
]