Совокупная сумма последнего элемента массива - PullRequest
0 голосов
/ 09 мая 2018

Сценарий: мне нужно объединить последнюю версию баланса всех клиентов в конкретном отделении банка

Документ в монго, который должен быть агрегирован

{
    "_id" : {
        "AccountNumber" : "123",
        "branchId" : "AXC",
        "@objectName" : "AccountBalance"
    },
    "Versions" : [ 
        {
            "value" : NumberDecimal("96562.88"),
            "version" : NumberLong(1)
        },
            {
            "value" : NumberDecimal("9612.88"),
            "version" : NumberLong(2)
        }
    ]
}

Я пробовал это, но возвращает 0 для результата:

db.getCollection('AccountInfo').aggregate([
  { "$project": { "Versions": { "$slice": [ "$Versions", -1 ] } } },
  { "$match": {    
    "_id.@objectName" : "AccountBalance",
  }},
  { "$group": { "_id": "$_id.branchId", "total": { "$sum": "$Versions.value" } } },
  { "$sort": { "total": -1 } }
])

Любая помощь приветствуется.

Ответы [ 2 ]

0 голосов
/ 09 мая 2018

Если массив Versions может иметь записи в любом порядке, то если последний элемент имеет versions.value меньше, чем любой предыдущий элемент, агрегация может быть неправильной (короче, если массив version не является порядком в versions.valueполе, последний элемент не даст правильного ответа).Следующая агрегация не зависит от позиции элементов массива, а сортирует элементы массива на основе поля versions.value для комбинированного ключа, номера счета и идентификатора филиала.

    db.bank.aggregate([{"$match":{"_id.@objectName":"AccountBalance"}},{"$unwind":{"path":"$Versions"}},{"$sort":{"Versions.version":-1}},{"$group":{"_id":{"accno":"$_id.AccountNumber","branchid":"$_id.branchId"},"value":{"$first":"$Versions.value"}}},{"$group":{"_id":"$_id.branchid","total":{"$sum":"$value"}}}])
0 голосов
/ 09 мая 2018

Вы были не далеко, операция, которую вы действительно хотите, это $arrayElemAt вместо

db.getCollection('AccountInfo').aggregate([
  { "$match": { "_id.@objectName" : "AccountBalance" }},
  { "$group": {
    "_id": "$_id.branchId",
    "total": { 
      "$sum": {
        "$arrayElemAt": [ "$Versions.value", -1 ]
      }
    }
  }},
  { "$sort": { "total": -1 } }
])

$slice возвращает "массив", поэтому вам все еще нужно $sum элементов:

db.getCollection('AccountInfo').aggregate([
  { "$match": { "_id.@objectName" : "AccountBalance" }},
  { "$group": {
    "_id": "$_id.branchId",
    "total": { 
      "$sum": {
        "$sum": { "$slice": [ "$Versions.value", -1 ] }
      }
    }
  }},
  { "$sort": { "total": -1 } }
])

Но обычно лучше получить единственный элемент, когда вы действительно это имеете в виду. Используйте $slice только там, где вы на самом деле имеете в виду «несколько» элементов массива.

Если вы точно не знали, что "version" был «последним» элементом массива, вы можете сопоставить его с $indexOfArray и $max:

db.getCollection('AccountInfo').aggregate([
  { "$match": { "_id.@objectName" : "AccountBalance" }},
  { "$group": {
    "_id": "$_id.branchId",
    "total": { 
      "$sum": {
        "$arrayElemAt": [
          "$Versions.value",
          { "$indexOfArray": [
            "$Versions.version",
            { "$max": "$Versions.version" }
          ]}
        ]
      }
    }
  }},
  { "$sort": { "total": -1 } }
])

Также научитесь «всегда» $match первым и не $project элементам, которые вы можете сделать то же самое «inline» в пределах $group. Это делает ваш запрос намного более эффективным.

Все возвращают один и тот же результат:

{ "_id" : "AXC", "total" : NumberDecimal("9612.88") }
...