我在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总是具有某些类型,“ default”总是与现有类型相关。
是否可以使用字段值(方案中的contracts.type)作为字段名称来从business.contract_settings获取设置?
请注意,contract_settings可以包含任意名称,因此我不能使用这样的解决方案 similar problem
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
答案 0 :(得分: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
}
}
])