Pymongo использует сортировку с $elemMatch не работает

У меня был такой образец данных:

[
{
    "_id": 1,
    "host": "host1",
    "type": "type1",
    "data": [
        {
            "t": 10000,
            "v": 90
        },
        {
            "t": 10001,
            "v": 94
        },
    ]
},
{
    "_id": 2,
    "host": "host1",
    "type": "type1",
    "data": [
        {
            "t": 10000,
            "v": 99
        },
        {
            "t": 10001,
            "v": 93
        },
    ]
},
{
    "_id": 3,
    "host": "host1",
    "type": "type1",
    "data": [
        {
            "t": 10000,
            "v": 94
        },
        {
            "t": 10001,
            "v": 100
        },
    ]
}]

мой запрос:

my_filter = {'host': 'host1', 'type': 'type1', 'data': {'$elemMatch': {'t': 10000}}}
projection = {'host': 1, 'type': 1, 'data': {'$elemMatch': {'t': 10000}}}
sort_key = 'data.0.v'

rs = db.find(my_filter, projection).sort(sort_key, 1)

rs = list(rs)
for v in rs:
    print(v["data"][0]['v'])

но такой вывод работает:

98
98
98
96
100
98
98

Уведомление:

  • теперь используйте: Python == 3.6.9, pymongo == 3.10.1, MongoDB == 4.2.6
  • длина документов 10000, длина вложенного массива 1440
  1. Мне нужны только данные, соответствующие условиям Nested Array, а не все, потому что это может быть большой массив.
  2. Мне нужны данные сортировки, но я не могу изменить порядок записи
  3. Я также использовал $aggregate, но когда данные большие, производительность плохая, поэтому я надеюсь сделать какую-нибудь операцию с find()

$агрегировать следующим образом:

    rs = db.aggregate([
    {"$match": {'host': 'host1', 'type': 'type1', 'data': {'$elemMatch': {'t': 10000}}}},
    {"$project": {'host': 1, 'type': 1,
                  'data': {"$filter": {
                      "input": "$data",
                      "as": "data",
                      "cond": {"$eq": ["$$data.t", 10000]}}
                  }
                  }},
    {"$sort": {'data.0.v': 1}}])

извините за мой плохой английский, но есть ли здесь хорошее решение?

У вас есть индекс по этим полям?

Wernfried Domscheit 22.12.2020 09:52

Какие версии Mongodb, python и pymongo вы используете?

Belly Buster 22.12.2020 10:37

Python == 3.6.9, пимонго == 3.10.1, версия монго == 4.2.6

Wynter 22.12.2020 11:34

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

Wynter 22.12.2020 11:58
Использование JavaScript и MongoDB
Использование JavaScript и MongoDB
Сегодня я собираюсь вкратце рассказать о прототипах в JavaScript, а также представить и объяснить вам работу с базой данных MongoDB.
1
4
323
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Я не смог воспроизвести вашу проблему, используя версии программного обеспечения, которые вы упомянули. Если у вас есть bash и docker, вы можете увидеть, отличаются ли ваши результаты:

PROJECT_NAME=sort_with_elemmatch

MONGODB_VERSION=4.2.6
PYTHON_VERSION=3.6.9
PYMONGO_VERSION=3.10.1

docker network create local_temp 2> /dev/null
docker run --rm --network local_temp -d --name mongodb_temp mongo:${MONGODB_VERSION}

cd "$(mktemp -d)" || exit

cat << EOF > requirements.txt
pymongo==${PYMONGO_VERSION}
EOF

cat << 'EOF' > ${PROJECT_NAME}.py
from pymongo import MongoClient
from random import randint

db = MongoClient('mongodb://mongodb_temp')['mydatabase'].mycollection

for i in range(20):
    db.insert_one(
    {
        "host": "host1",
        "type": "type1",
        "data": [
            {
                "t": 10000,
                "v": randint(0, 100)
            },
            {
                "t": 10001,
                "v": randint(0, 100)
            },
        ]
    })

my_filter = {'host': 'host1', 'type': 'type1', 'data': {'$elemMatch': {'t': 10000}}}
projection = {'host': 1, 'type': 1, 'data': {'$elemMatch': {'t': 10000}}}
sort_key = 'data.0.v'

rs = db.find(my_filter, projection).sort(sort_key, 1)

rs = list(rs)
for v in rs:
    print(v["data"][0]['v'])
EOF

cat << EOF > Dockerfile
FROM python:${PYTHON_VERSION}
COPY ./* /
RUN pip install -r /requirements.txt
CMD ["python", "${PROJECT_NAME}.py"]
EOF

docker build --tag ${PROJECT_NAME}:latest .
docker run --rm --network local_temp --name ${PROJECT_NAME} ${PROJECT_NAME}:latest
docker stop "$(docker ps -a -q --filter name=mongodb_temp)" > /dev/null
docker image rm ${PROJECT_NAME}:latest > /dev/null
docker network rm local_temp > /dev/null

печатает:

5
17
18
19
20
28
29
37
59
59
61
63
64
66
68
77
82
82
100
100

спасибо за попытку, я нашел вопрос, пожалуйста, посмотрите ответ ниже

Wynter 23.12.2020 08:39
Ответ принят как подходящий

Я нашел проблему. Кажется, это связано с порядком ключей во встроенном массиве:

    for i in range(20):
        data_0, data_1 = {"t": 10000, "v": random.randint(0, 100)}, {"t": 10001, "v": random.randint(0, 100)}
        insert_d = {
            "host": "host1",
            "type": "type1",
            "data": [data_0, data_1] if i != 10 else [data_1, data_0]
        }
        db.insert_one(insert_d)

    my_filter = {'host': 'host1', 'type': 'type1', 'data': {'$elemMatch': {'t': 10000}}}
    projection = {'host': 1, 'type': 1, 'data': {'$elemMatch': {'t': 10000}}}
    sort_key = 'data.0.v'

    rs = db.find(my_filter, projection).sort(sort_key, 1)

    rs = list(rs)
    for v in rs:
        print(v["data"][0]['v'])

если вы попробуете это, вы обнаружите, что сортировка не работает должным образом. Большинство значений упорядочены, но одно неупорядочено, поэтому я хочу знать, как работает сортировка.

Я искал, и, возможно, это может помочь ... stackoverflow.com/questions/28889240/…

Belly Buster 23.12.2020 11:47

Другие вопросы по теме