запись логики условного умножения в массив запроса mongo

#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 /

Надеюсь, что это решит вашу проблему.