Mongodb:根据条件填充

时间:2021-06-14 16:27:10

标签: mongodb mongoose-populate

我有一些集合,我正在尝试将日志对象转换为其详细信息(使用 populate)。

Companies(公司及其用户):

[
    {
        _id: "comp123",
        companyId: "compName123",
        users: [
            { user: "user111", status: "active"},
            { user: "user222", status: "active"},
        ]
    },
    {
        _id: "comp456",
        name: "compName456",
        users: [
            { user: "user333", status: "active"}
        ]
    },
    {
        _id: "comp789",
        name: "compName789",
        users: [
            { user: "user444", status: "inactive"}
        ]
    },
]

Users:

[
    {_id: "user111", firstName: "userName111"},
    {_id: "user222", firstName: "userName222"},
    {_id: "user333", firstName: "userName333"},
    {_id: "user444", firstName: "userName444"},
]

我正在尝试将 log 集合转换为数据。

examples:

对于 log 的第一个对象:

{
   companyId: "comp123",
   actionDetails: [
      entities: [
         { id: "user111", entityType: "User"}
      ]
   ]
},

我希望它返回:

{
    companyId: {_id: "comp123", name: "compName123"}, // taken from companies
    userId: { _id: "user111", firstName: "userName111"}, // taken from users
    // Does company=comp123 that has a user with user=user111 and status=active exist?
    isUserActiveInCompany: true
}

另一个日志示例:

{
    companyId: "comp456",
    actionDetails: [
        entities: [
            { id: "user444", entityType: "User"}
        ]
    ]
}

输出为:

{
    companyId: {_id: "comp456", name: "compName456"}, // taken from companies
    userId: { _id: "user444", firstName: "userName444"}, // taken from users
    isUserActiveInCompany: false // Does company=comp456 that has a user with user=user444 and status=active exist?
}

最后一个重要的日志示例:

{
    companyId: "comp789",
    actionDetails: [
        entities: [
            { id: "attr333", entityType: "Attribute"}
        ]
    ]
}

输出:

{
    companyId: {_id: "comp789", name: "compName789"}, // taken from companies
    userId: {}, // taken from users (entityType is Attribute so we ignore it)
    isUserActiveInCompany: null // entityType is Attribute so we ignore it
}

如果会有comp789和user444的日志,isUserActiveInCompany应该是false(因为用户在他的公司是不活跃的)。

目前,我这样做:

populate([
    {
        path: "actionDetails.entities.id",
        select: "id firstName",
    },
    {
        path: "companyId",
        select: "name",
    },
]

感谢任何帮助!

1 个答案:

答案 0 :(得分:1)

将下面的聚合管道代码转换为 Mongoose Equivalent 以获得您想要的输出。

db.log.aggregate([
  {
    '$match': {
      // <-- I highly recommend that you use a `$match` condition since there are 2 lookup operators in the aggregation which will significantly increase execution time.
    }
  },
  {
      '$lookup': {
      'from': 'Companies',
      'let': {'cId': '$companyId'},
      'pipeline': [
        {
          '$match': {
            '$expr': {
              '$eq': ['$_id', '$$cId']
            }
          }
        },
        {
          "$project": {
            'company': {
              "_id": "$_id",
              "companyName": "$companyId"
            },
            'users': {
              "$filter": {
                'input': "$users",
                'as': "usr",
                'cond': {
                  "$eq": ["$$usr.status", "active"],
                },
              },
            },
          }
        },
      ],
      'as': 'companyDetails'
    }
  },
  {
    '$unwind': {
      'path': "$actionDetails",
    }
  }, 
  {
    '$unwind': {
    'path': "$actionDetails.entities",
    }
  }, 
  {
    '$lookup': {
      'from': 'Users',
      'let': {"uId": "$actionDetails.entities.id"},
      'pipeline': [
        {
          "$match": {
            "$expr": {
              "$eq": ["$_id", "$$uId"],
            },
          },
        },
        {
          "$project": {
            "firstName": 1,
          },
        },
      ],
      'as': "userDetails",
    }
  },
  {
    '$project': {
      "companyId": {"$arrayElemAt": ["$companyDetails.company", 0]},
      "userId": {
        "_id": "$actionDetails.entities.id",
        "firstName": {"$arrayElemAt": ["$userDetails.firstName", 0]},
      },
      "isUserActiveInCompany": {
        "$switch": {
          "branches": [
            {
              'case': {
                "$ne": ["$actionDetails.entities.entityType", "User"]
              },
              'then': null,
            },
            {
              'case': {
                "$in": [
                  "$actionDetails.entities.id",
                  {
                    "$map": {
                      'input': {"$arrayElemAt": ["$companyDetails.users", 0]},
                      'as': "elem",
                      'in': "$$elem.user"
                    }
                  }
                ]
              },
              'then': true,
            },
          ],
          'default': false,
        }
      }
    }
  }
], {
  'allowDiskUse': true,
});

如果您想要每个阶段的完整解释和逻辑,请告诉我。