У меня был такой образец данных:
[
{
"_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
Уведомление:
$агрегировать следующим образом:
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}}])
извините за мой плохой английский, но есть ли здесь хорошее решение?
Какие версии Mongodb, python и pymongo вы используете?
Python == 3.6.9, пимонго == 3.10.1, версия монго == 4.2.6
Поскольку во встроенном массиве слишком много ключей, я думаю, что создать индекс для каждого требования непросто, поэтому я пытаюсь найти другой способ.

Я не смог воспроизвести вашу проблему, используя версии программного обеспечения, которые вы упомянули. Если у вас есть 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
спасибо за попытку, я нашел вопрос, пожалуйста, посмотрите ответ ниже
Я нашел проблему. Кажется, это связано с порядком ключей во встроенном массиве:
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/…
У вас есть индекс по этим полям?