MongoDB: агрегирование, $ group по нескольким (двум) полям, с сортировкой (получением последних) результатов - PullRequest
1 голос
/ 07 августа 2020

Я имею дело с довольно странным случаем агрегации в Mon go. У меня довольно стандартная коллекция со следующей схемой / полями:

{
  price: Number,
  conneected_realm_id: Number, /** <= destination or warehouse pointer */
  item.id: Number, /** Some kind of SKU */
  last_modified: Number /** Unix timestamp, the latest documents has greater results, always */
}

И мой запрос на агрегирование, в котором я всегда был уверен, возвращает мне -latest results, но, как я теперь понял, на самом деле это не так. 't.

ПРОБЛЕМА:

Пример MongoPlayground

Коллекция получает данные в реальном времени и сохраняет их. Каждый item со своим собственным полем connected_realm_id (это хранилище / указанные данные) имеет свои уникальные временные метки. Итак, это похоже на:

  item: 168652
  in warehouses: 1602 | 1063
  timestamps:  -latest for each
                  7       5
                  4       3 /** <= this are outdated timestamps */
                  2       1 /** <= and so is this */

Итак, по моей агрегации в MongoPlayground, я хочу получить следующие данные

All original documents with:
 item: 168652
 groupedBy: { 1602 and 7 }, { 1603 and 5 } /** latest ($max) timestamps for each warehouse */

вместо этого я получаю каждую уникальную временную метку для каждого склада, но я это не нужно. Итак, вопрос: можно ли получить следующие данные?

Дополнительная информация:

  • Mon go v4.2, поэтому я мог бы использовать почти все операторы, кроме $replaceOne
  • Я знаю, я мог бы решить эту проблему, сделав N (количество складов) запросов или через .eachAsync, но это не решение, потому что у меня 200+ складов. Я могу добавить еще один этап в свой запрос (который достаточно длинный, поверьте мне), но я не могу сделать N-запрос к БД с коллекцией {$match: { connected_realm_id: value, last_modified: -latest } }
  • уже имеет индексы, один из них равно compound на connected_realm_id && last_modified, поэтому, если я использую $match или .find(), я получаю предварительно отсортированные значения из БД.
  • Просто чтобы прояснить, все это дело в сохранении / фильтрации документов по умолчанию $$ROOT. Поэтому мне не нужно получать последнюю временную метку для каждого склада . Я могу получить эти данные другим, более эффективным способом, все дело в фильтрации / сохранении поля {data: $$ROOT}

Ответы [ 2 ]

1 голос
/ 07 августа 2020

Я хочу получить следующие данные

 item: 168652
 groupedBy: { 1602 and 7 }, { 1603 and 5 }
  1. Вам нужно сгруппировать в элементе последним
  2. Первоначально вам нужно сгруппировать в области , тогда вам нужно получить последнюю временную метку, т.е. max

play

db.collection.aggregate([
  {
    $group: {
      _id: {
        connected_realm_id: "$connected_realm_id"
      },
      "data": {
        "$max": "$last_modified"
      },
      "item": {
        "$first": "$item.id"
      }
    }
  },
  {
    $project: {
      "connected_realm_id": "$_id.connected_realm_id",
      "last_modified": "$data",
      "item": 1,
      "_id": 0
    }
  },
  {
    "$group": {
      "_id": "$item",
      "groupedBy": {
        "$push": "$$ROOT"
      }
    }
  }
])

EDIT:

этот?

db.collection.aggregate([
  {
    $group: {
      _id: {
        connected_realm_id: "$connected_realm_id",
        latest_timestamp: {
          $max: "$last_modified"
        },
        
      },
      data: {
        $push: "$$ROOT"
      }
    }
  },
  {
    "$unwind": "$data"
  },
  {
    $group: {
      _id: {
        connected_realm_id: "$data.connected_realm_id"
      },
      "data": {
        "$max": "$data.last_modified"
      },
      "item": {
        "$first": "$data.item.id"
      }
    }
  },
  {
    $project: {
      "connected_realm_id": "$_id.connected_realm_id",
      "last_modified": "$data",
      "item": 1,
      "_id": 0
    }
  },
  {
    "$group": {
      "_id": "$item",
      "groupedBy": {
        "$push": "$$ROOT"
      }
    }
  }
])

Обновление:

Как OP, полученный из приведенного выше редактирования, это решает проблему OP

db.collection.aggregate([
  {
    $group: {
      _id: {
        connected_realm_id: "$connected_realm_id",
        latest_timestamp: {
          $max: "$last_modified"
        },
        
      },
      data: {
        $push: "$$ROOT"
      }
    }
  },
  {
    "$unwind": "$data"
  },
  {
    $group: {
      _id: {
        connected_realm_id: "$data.connected_realm_id"
      },
      "data": {
        "$max": "$data.last_modified"
      },
      "item": {
        "$push": "$data"
      }
    }
  }
])
0 голосов
/ 07 августа 2020

Правильное (окончательное решение) в MongoPlayground

Набор данных:

[
  {
    item: {
      id: 168652
    },
    connected_realm_id: 1602,
    last_modified: 1596719280
  },
  {
    item: {
      id: 168652
    },
    connected_realm_id: 1602,
    last_modified: 1596719280
  },
  {
    item: {
      id: 168652
    },
    connected_realm_id: 1602,
    last_modified: 1596719280
  },
  {
    item: {
      id: 168652
    },
    connected_realm_id: 1602,
    last_modified: 1596719280
  },
  {
    item: {
      id: 168652
    },
    connected_realm_id: 1602,
    last_modified: 2
  },
  {
    item: {
      id: 168652
    },
    connected_realm_id: 1602,
    last_modified: 3
  },
  {
    item: {
      id: 168652
    },
    connected_realm_id: 1602,
    last_modified: 4
  },
  {
    item: {
      id: 168652
    },
    connected_realm_id: 1602,
    last_modified: 5
  },
  {
    item: {
      id: 168652
    },
    connected_realm_id: 1602,
    last_modified: 1596719280
  },
  {
    item: {
      id: 168652
    },
    connected_realm_id: 1602,
    last_modified: 1596719280
  },
  {
    item: {
      id: 168652
    },
    connected_realm_id: 1603,
    last_modified: 1596719267
  },
  {
    item: {
      id: 168652
    },
    connected_realm_id: 1603,
    last_modified: 1596719267
  },
  {
    item: {
      id: 168652
    },
    connected_realm_id: 1603,
    last_modified: 1596719267
  },
  {
    item: {
      id: 168652
    },
    connected_realm_id: 1603,
    last_modified: 1596719267
  },
  {
    item: {
      id: 168652
    },
    connected_realm_id: 1603,
    last_modified: 1
  },
  {
    item: {
      id: 168652
    },
    connected_realm_id: 1603,
    last_modified: 2
  },
  {
    item: {
      id: 168652
    },
    connected_realm_id: 1603,
    last_modified: 3
  },
  {
    item: {
      id: 168652
    },
    connected_realm_id: 1603,
    last_modified: 4
  },
  {
    item: {
      id: 168652
    },
    connected_realm_id: 1603,
    last_modified: 5
  },
  {
    item: {
      id: 168652
    },
    connected_realm_id: 1603,
    last_modified: 1596719267
  }
]

Агрегационный запрос

db.collection.aggregate([
  {
    $group: {
      _id: {
        connected_realm_id: "$connected_realm_id"
      },
      latest: {
        $max: "$last_modified"
      },
      data: {
        $push: "$$ROOT"
      }
    }
  },
  {
    $unwind: "$data"
  },
  {
    $addFields: {
      "data.latest": {
        $cond: {
          if: {
            $eq: [
              "$data.last_modified",
              "$latest"
            ]
          },
          then: "$latest",
          else: "$false"
        }
      }
    }
  },
  {
    "$replaceRoot": {
      "newRoot": "$data"
    }
  },
  {
    "$match": {
      "latest": {
        "$exists": true,
        "$ne": null
      }
    }
  }
])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...