#mongodb #mongoose
#mongodb #mongoose
Вопрос:
У меня есть данные json следующим образом:
[{
finale: [ { sign: '~', prob: 0.5 },
{ sign: '~', prob: 0.4 } ]
},
{
finale: [ { sign: '~', prob: 0.7 },
{ sign: '>', prob: 0.25 } ]
}]
Теперь я хочу, чтобы результат был примерно таким:
[{
result : {
sign: '~', prob: 0.2
}
},
{
result : {
sign: '>', prob: 0.25
}
}]
Вот моя логика для вывода:
Если элементы массива в ‘finale’ имеют все «~» в элементе ‘sign’, то я хочу, чтобы результат имел умножение всех полей ‘prob’ в массиве, который оказывается:
0.5 * 0.4 = 0.2
Однако, если есть хотя бы один знак, который является либо ‘>’, либо ‘<‘, мне просто нужно скопировать одно и то же из ‘sign’ и ‘prob’ в результате, игнорируя все остальные значения, как показано во втором результате выше
[Примечание: в массиве может быть только один из ‘<‘ или ‘>’. Элементы массива внутри «финала» могут содержать не более 3 элементов, но в нем должно быть не менее 1 элемента. Порядок элементов также может быть случайным.]
Комментарии:
1. упорядочен ли ваш массив? Я имею в виду, «<» и «>» всегда после «~»?
2. ваш массив ограничен 2 элементами?
3. @Dada Нет, в массиве не будет никакого порядка, и массив может содержать не более 3 элементов и не менее 1 элемента. Я знаю, это звучит слишком сложно, верно?
Ответ №1:
Я использую платформу агрегации MongoDB.
Этот запрос работает с этим ограничением: в каждом документе не может существовать более 1 «<» или 1 «>». В принципе, каждый объект может иметь несколько «~», но 0 или 1 «>» или «<«.
Главное — сгруппировать по знаку, а затем отклонить каждый объект, имеющий «~», за исключением случая, когда он имеет только «~».
db.Test1.aggregate([
{
$unwind:"$finale"
},
{
$group:{
_id: {_id: "$_id", sign:"$finale.sign"},
finaleitems:{$push:"$finale"}
}
},
{
$match: {
$or: [
{$and:[ {finaleitems: {$size: 1}}, {$or:[ {"_id.sign":">"}, {"_id.sign":"<"} ]} ]},
{$or:[ {finaleitems: {$size: 2}}, {finaleitems: {$size: 3}} ]}
]
}
},
{
$project: {
_id: 1,
finaleitems: 1,
result: {
$cond: [{$eq:["$_id.sign","~"]},
{
$reduce: {
input: "$finaleitems",
initialValue: 1,
in: { $multiply : ["$value", "$this.prob"] }
}
},
{$arrayElemAt:["$finaleitems",0]}]
}
}
}
]);
ВВОД:
{
"_id" : ObjectId("58033a8bd63cf401292fe09a"),
"finale" : [
{
"sign" : "~",
"prob" : 0.5
},
{
"sign" : "~",
"prob" : 0.4
}
]
}
{
"_id" : ObjectId("58033a98d63cf401292fe09d"),
"finale" : [
{
"sign" : "~",
"prob" : 0.7
},
{
"sign" : ">",
"prob" : 0.25
}
]
}
{
"_id" : ObjectId("58035251d63cf401292fe0a0"),
"finale" : [
{
"sign" : "<",
"prob" : 0.7
},
{
"sign" : "~",
"prob" : 0.25
}
]
}
{
"_id" : ObjectId("5803622dd63cf401292fe0a3"),
"finale" : [
{
"sign" : "~",
"prob" : 0.7
},
{
"sign" : ">",
"prob" : 0.25
}
]
}
ВЫВОД:
{
"_id" : {
"_id" : ObjectId("5803622dd63cf401292fe0a3"),
"sign" : ">"
},
"finaleitems" : [
{
"sign" : ">",
"prob" : 0.25
}
],
"result" : {
"sign" : ">",
"prob" : 0.25
}
}
{
"_id" : {
"_id" : ObjectId("58035251d63cf401292fe0a0"),
"sign" : "<"
},
"finaleitems" : [
{
"sign" : "<",
"prob" : 0.7
}
],
"result" : {
"sign" : "<",
"prob" : 0.7
}
}
{
"_id" : {
"_id" : ObjectId("58033a98d63cf401292fe09d"),
"sign" : ">"
},
"finaleitems" : [
{
"sign" : ">",
"prob" : 0.25
}
],
"result" : {
"sign" : ">",
"prob" : 0.25
}
}
{
"_id" : {
"_id" : ObjectId("58033a8bd63cf401292fe09a"),
"sign" : "~"
},
"finaleitems" : [
{
"sign" : "~",
"prob" : 0.5
},
{
"sign" : "~",
"prob" : 0.4
}
],
"result" : 0.2
}
Как вы можете видеть, что возвращается больше свойств, они вам не нужны, но я думаю, что это хорошо для отладки того, что создает конвейер.
Я использую Mongo DB 3.4RC, который имеет $reduce
функцию: https://docs.mongodb.com/master/reference/operator/aggregation/reduce /
Надеюсь, что это решит вашу проблему.