PyMon go - выбрать объект из массива, имеющего максимальное значение - PullRequest
1 голос
/ 13 апреля 2020

Документ в моей БД выглядит так:

 {
    "_id": ObjectId("5e92e63fad262707ff301d6c"),
    "uknum": 30,
    "area": "bath",
    "ukelectors": 62355,
    "ukresults": [
      {
        "party": "con",
        "leader": "thatcher",
        "ukvotes": 22544
      },
      {
        "party": "lab",
        "leader": "foot",
        "ukvotes": 7259
      },
      {
        "party": "sdp",
        "leader": "jenkins",
        "ukvotes": 17240
      },
      {
        "party": "eco",
        "leader": "whittaker",
        "ukvotes": 441
      }
    ]
  }

Требование:

Мне нужно создать запрос в python, чтобы получить имя партия, которая выиграла area: bath. По сути, проверьте, кто набрал максимальное количество голосов, и выберите эту партию.

Идея заключалась в том, чтобы использовать $ max конвейер агрегации, но, похоже, он не работает.

Ответы [ 2 ]

0 голосов
/ 14 апреля 2020

Следующий запрос агрегирования печатает поддокумент ukresults с максимальным количеством голосов.

Оператор агрегирования $max не может быть применен непосредственно к массиву ukresults, так как массив содержит вложенные документы, а не скалярные значения, такие как числа. Таким образом, мы используем $reduce оператор агрегирования для извлечения поддокумента с максимальным количеством голосов. Обратите внимание, что использование оператора $reduce - это операция сокращения в массиве, поэтому используется $max - разница в типе данных элемента массива.

PyMon go код:

import pymongo
import pprint
client = pymongo.MongoClient()
collection = client.test.testCollection

pipeline = [
  { 
      "$match": { "area": "bath" } 
  },
  { 
      "$addFields": {
          "maxvotes": {
              "$reduce": {
                  "input": "$ukresults",
                  "initialValue": { "ukvotes": 0  },
                  "in": {
                      "$cond": [
                          { "$gt": [ "$$this.ukvotes", "$$value.ukvotes"] }, 
                                       "$$this",
                                       "$$value"
                      ]
                  }
              }
          }
      }
  },
  { 
      "$project": {
          "_id": 0,
          "area": 1,
          "maxvotes": 1
      }
  }
]

pprint.pprint(list(collection.aggregate(pipeline)))

Выход:

[{'area': 'bath',
  'maxvotes': {'leader': 'thatcher', 'party': 'con', 'ukvotes': 22544.0}}]
0 голосов
/ 13 апреля 2020

Это можно сделать с помощью одного из запросов агрегации :

Запрос 1: Без использования $unwind, с помощью $reduce на массиве:

db.collection.aggregate([
  { $match: { area: "bath" } },
  {
    $addFields: {
      ukresults: {
        $let: {
          vars: {
            res: {
              $reduce: {
                input: "$ukresults",
                initialValue: { votes: 0, party: {} },
                in: {
                  votes: {
                    $cond: [
                      { $gt: ["$$this.ukvotes", "$$value.votes"] },
                      "$$this.ukvotes",
                      "$$value.votes",
                    ],
                  },
                  party: {
                    $cond: [
                      { $gt: ["$$this.ukvotes", "$$value.votes"] },
                      "$$this",
                      "$$value.party",
                    ],
                  },
                },
              },
            },
          },
          in: "$$res.party",
        },
      },
    },
  },
]);

Тест: MongoDB-Playground

Запрос 2: С использованием $unwind :

db.collection.aggregate([
  {
    $match: {
      area: "bath"
    }
  },
  {
    $unwind: {
      path: "$ukresults",
      preserveNullAndEmptyArrays: true
    }
  },
  {
    $sort: {
      "ukresults.ukvotes": -1
    }
  },
  {
    $limit: 1
  }
])

Тест: MongoDB-Playground

Я бы сказал, что эти два могут работать хорошо, в основном мы работаем с одним документом (Потому что у нас $match в качестве первого этапа), возможно, для первого запроса может потребоваться хитрость для итерации, если у вас больше элементов в массиве, попробуйте и выберите тот, который больше всего помогает.

Ref: Проверьте этот документ Pymon go для примеров агрегации: Pymon go -aggregation .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...