为 Mongodb 聚合中的每个数组元素匹配并添加新字段

Match and add new field to each array elements in Mongodb aggregation

我下面有两个集合,我正在使用聚合和合并创建视图 table。

account table:
{
    "_id": {
        "$oid": "5f61b573db16185cebfeaaf9"
    },
    "status": "ACTIVE",
    "personalInfo": {
        "entityName": "John Doe",
        ...
    },
    "createdDateTime": {
        "$date": "2020-09-16T06:49:23.103Z"
    },
    "modifiedDateTime": {
        "$date": "2020-09-16T06:49:23.103Z"
    }
}

account_transactions:
{
    "_id": {
        "$oid": "5f61b5b3db16185cebfeab0c"
    },
    "accountId": "5f61b573db16185cebfeaaf9",
    "transactionType": "Payment",
    "transactionStatus": "NEW",
    "createdDate": {
        "$date": "2020-09-16T06:50:27.305Z"
    },
    "createdBy": "sujal.shakya@joinsage.com",
    "lastModifiedDate": {
        "$date": "2020-09-16T10:23:06.617Z"
    }
}

{
    "_id": {
        "$oid": "5f61b5b3db16185cebfeab0f"
    },
    "accountId": "5f61b573db16185cebfeaaf9",
    "transactionType": "Credit",
    "createdDate": {
        "$date": "2020-09-16T06:50:27.305Z"
    },
    "createdBy": "sujal.shakya@joinsage.com",
    "lastModifiedDate": {
        "$date": "2020-09-16T10:23:06.617Z"
    }
}

下面的 mongodb 查询创建一个视图 table 每个帐户都有多个交易(如果存在),如果不存在交易,则将虚拟交易添加到一些虚拟字段。

db.account.aggregate(
    [
        {
            $match: {
                'status': 'ACTIVE'
            }
        },

        {$addFields: {"accountId": {"$toString": "$_id"}}},

        {
            $lookup: {
                from: "account_transactions",
                localField: "accountId",
                foreignField: "accountId",
                as: "transactions"
            }
        },
        {
            "$project": {
                "accountType": 1,
                "transactions": {
                    "$cond": [
                        { "$eq": [ "$transactions", [] ] },
                        {$concatArrays: [[{"lastModifiedDate": {$arrayElemAt: ["$account.modifiedDateTime",0]}, "transactionType" : "BLANK"}]] },//adds dummy fields
                        {"$filter": {
                        "input": "$transactions",
                        "as": "transactions",
                        "cond": {
                            "$or": [
                                {
                                    "$eq": [
                                        "$$transactions.transactionType",
                                        "Payment"
                                    ]
                                },
                                {
                                    "$eq": [
                                        "$$transactions.transactionType",
                                        "Sale"
                                    ]
                                },
                                {
                                    "$eq": [
                                        "$$transactions.transactionType",
                                        "Debit"
                                    ]
                                }

                            ]
                        }
                    }
                    }
                },
                "createdBy": 1
            }
        },
        {$merge: {into: "account_view_table", on: "_id", whenMatched: "replace", whenNotMatched: "insert"}}
    ])

我现在需要做的是在视图中添加一个新字段table 上面通过匹配交易类型为每个交易创建了一个字段。例如:如果一个账户有多个交易,每个交易都有不同的交易类型,那么检查每个交易的交易类型,并在每个 like 上添加新字段“transactionTypeOrder”:

我一直在尝试不同的方法,但没有任何效果

 {$addFields: {"transactions.transactionTypeOrder" : 
             {
                 $cond: [{$in:["$transactions.transactionType",["Payment"]]},"1",
                     {$cond: [ {$in:["$transactions.transactionType",["Sale"]]},"2",
                             {$cond: [{$in:["$transactions.transactionType",["Debit"]]},"3", "4" ]}
                             ]}
                             ]
             }
 }},

因此,如果 transactionType == "Payment" 添加 transactionTypeOrder: 1,如果 transactionType == "Sales" 添加 transactionTypeOrder: 2 等等。我正在寻找的输出如下所示:

第二个案例的案例也检查另一个字段: 在相同的交易中,我还必须对不同的字段进行另一次检查,以检查“transactionStatus”字段是否存在,如果不存在,则将“transactionStatusOrderAsc”字段添加为“####”,将“transactionStatusOrderDsc”添加为“~~~”和如果存在与“transactionStatus”相同的值,那么输出将如下所示:

所以基本上,我必须检查 transactionType 并添加新的 Filed,同时还要检查 transactionStatus 和两个需要的字段。

 //result view table
        {
            "_id": {
                "$oid": "5f61b573db16185cebfeaafd"
            },
            //...other fields.
            "transactions": [{
                "transactionType": "Payment",
                "transactionTypeOrder": 1,
                "transactionStatus": "New",
                "transactionStatusOrderAsc": "New",
                "transactionStatusOrderDsc": "New"
            },
        
            {
                "transactionType": "Sales",
                "transactionTypeOrder": 2,
                "transactionStatusOrderAsc": "####", //since transactionStatus field doesn't exist here
                "transactionStatusOrderDsc": "~~~~"
            },
        
            {
                "transactionType": "Debit",
                "transactionTypeOrder": 3,
                "transactionStatus": "Old",
                "transactionStatusOrderAsc": "Old",
                "transactionStatusOrderDsc": "Old"
            }
        
            ]
        }

您可以使用 $map to apply to each element of your array, and $switch 检查值并添加您的字段。

db.account.aggregate([
  {
    $match: {
      "status": "ACTIVE"
    }
  },
  {
    $addFields: {
      "accountId": {
        "$toString": "$_id"
      }
    }
  },
  {
    $lookup: {
      from: "account_transactions",
      localField: "accountId",
      foreignField: "accountId",
      as: "transactions"
    }
  },
  {
    "$project": {
      "accountType": 1,
      "createdBy": 1,
      transactions: /**adds dummy fields*/
      {
        "$map": {
          "input": "$transactions",
          "as": "transactions",
          "in": {
            $switch: {
              branches: [
                {
                  case: {
                    $eq: [
                      "$$transactions.transactionType",
                      "Payment"
                    ]
                  },
                  then: {
                    transactionType: "$$transactions.transactionType",
                    transactionTypeOrder: 1
                  }
                },
                {
                  case: {
                    $eq: [
                      "$$transactions.transactionType",
                      "Sales"
                    ]
                  },
                  then: {
                    transactionType: "$$transactions.transactionType",
                    transactionTypeOrder: 2
                  }
                },
                {
                  case: {
                    $eq: [
                      "$$transactions.transactionType",
                      "Debit"
                    ]
                  },
                  then: {
                    transactionType: "$$transactions.transactionType",
                    transactionTypeOrder: 3
                  }
                },
                
              ],
              default: {
                transactionType: "$$transactions.transactionType",
                transactionTypeOrder: -1
              }
            }
          }
        }
      }
    }
  },
])

如果您需要每个交易的其他字段,您必须在每个案例条件中添加它们。 你可以测试一下here


根据第一条评论进行编辑

如果您必须包括所有交易字段,您可以使用 $mergeObjects 而不是手动创建对象。

db.account.aggregate([
  {
    $match: {
      "status": "ACTIVE"
    }
  },
  {
    $addFields: {
      "accountId": {
        "$toString": "$_id"
      }
    }
  },
  {
    $lookup: {
      from: "account_transactions",
      localField: "accountId",
      foreignField: "accountId",
      as: "transactions"
    }
  },
  {
    "$project": {
      "accountType": 1,
      "createdBy": 1,
      transactions: /**adds dummy fields*/
      {
        "$map": {
          "input": "$transactions",
          "as": "transactions",
          "in": {
            $switch: {
              branches: [
                {
                  case: {
                    $eq: [
                      "$$transactions.transactionType",
                      "Payment"
                    ]
                  },
                  then: {
                    $mergeObjects: [
                      "$$transactions",
                      {
                        transactionTypeOrder: 1
                      }
                    ]
                  }
                },
                {
                  case: {
                    $eq: [
                      "$$transactions.transactionType",
                      "Sales"
                    ]
                  },
                  then: {
                    $mergeObjects: [
                      "$$transactions",
                      {
                        transactionTypeOrder: 2
                      }
                    ]
                  }
                },
                {
                  case: {
                    $eq: [
                      "$$transactions.transactionType",
                      "Debit"
                    ]
                  },
                  then: {
                    $mergeObjects: [
                      "$$transactions",
                      {
                        transactionTypeOrder: 3
                      }
                    ]
                  }
                },
                
              ],
              default: {
                $mergeObjects: [
                  "$$transactions",
                  {
                    transactionTypeOrder: -1
                  }
                ]
              }
            }
          }
        }
      }
    }
  },
])

Test it here