【问题标题】:MongoDB: using field value as field nameMongoDB:使用字段值作为字段名称
【发布时间】:2020-07-17 17:52:20
【问题描述】:

我在 MongoDB 中有下一个示例文档。

db={
  "contracts": [
    {
      "bid": 1, // id in businesses collection
      "type": "A",
      "name": "N1"
    },
    {
      "bid": 1,
      "type": "B",
      "name": "N2"
    },
    {
      "bid": 1,
      "type": "C",
      "name": "N3"
    }
  ],
  "businesses": [
    {
      "id": 1,
      "contract_settings": {
        "A": {
          "price": 100
        },
        "B": {
          "price": 200
        },
        "default": "A"
      }
    }
  ]
}

我想根据合同的类型查找合同的价格。如果合约的类型不在contract_settings中,那么我应该使用默认值。

例如对于当前方案,我希望输出为

  "contracts": [
    {
      "bid": 1,
      "type": "A",
      "name": "N1",
      "price": 100
    },
    {
      "bid": 1,
      "type": "B",
      "name": "N2",
      "price": 200
    },
    {
      "bid": 1,
      "type": "C",
      "name": "N3",
      "price":100 // because default settings are settings for type "A"
    }
  ]
}

Contract_settings 总是有一些类型并且“默认”总是连接到现有类型。

是否可以使用字段值(方案中的contracts.type)作为字段名从businesss.contract_settings 中获取设置?

注意,contract_settings 可以包含任意名称,所以我不能使用这样的解决方案 similar problem

here is playground

PS。如果 contract_settings 是 jsonb 字段,并且使用这样的代码,可以解决 postgres 中的相同问题

    ((CASE WHEN businesses.contract_settings::jsonb ? contracts.contract_type::text
            THEN businesses.contract_settings -> contracts.contract_amount::text
            ELSE businesses.contract_settings -> (businesses.contract_settings ->> 'default') END)->>'price')::double precision

【问题讨论】:

    标签: mongodb aggregation-framework


    【解决方案1】:

    当你想在 Mongo 中“迭代”一个对象时,它会变得非常混乱,因为 Mongo 要求你将该对象转换为一个数组并对其使用数组操作。

    如果可能,我建议重新考虑 contract_setting 架构,话虽如此,鉴于当前结构,我将如何解决该问题:

    db.contracts.aggregate([
      {
        $lookup: {
          from: "businesses",
          localField: "bid",
          foreignField: "id",
          as: "businesses"
        }
      },
      {
        $unwind: "$businesses" /**I'm assuming there's always 1.*/
      },
      {
        $addFields: {
          matchedPrice: {
            $reduce: {
              input: {
                $filter: {
                  input: {
                    $objectToArray: "$businesses.contract_settings"
                  },
                  as: "setting",
                  cond: {
                    $eq: [
                      "$$setting.k",
                      "$type"
                    ]
                  }
                }
              },
              initialValue: null,
              in: "$$this.v.price"
            }
          }
        }
      },
      {
        $addFields: {
          price: {
            $ifNull: [
              "$matchedPrice",
              {
                $reduce: {
                  input: {
                    $filter: {
                      input: {
                        $objectToArray: "$businesses.contract_settings"
                      },
                      as: "setting",
                      cond: {
                        $eq: [
                          "$$setting.k",
                          "$businesses.contract_settings.default"
                        ]
                      }
                    }
                  },
                  initialValue: null,
                  in: "$$this.v.price"
                }
              }
            ]
          }
        }
      },
      {
        $project: {
          price: 1,
          bid: 1,
          type: 1,
          name: 1
        }
      }
    ])
    

    MongoPlayground

    【讨论】:

    • 很好,它正在工作,谢谢。但是你在“重新考虑 contract_setting 模式”下是什么意思?
    • 我的意思是用不同的格式保存数据,这样查询起来更容易
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-08
    • 1970-01-01
    • 2018-05-24
    • 2022-11-11
    • 2020-11-24
    相关资源
    最近更新 更多