#python #mongodb #mongodb-query
Вопрос:
У меня есть этот json-файл с примерно 14 массивами, каждый из которых содержит число, и я пытаюсь получить среднее значение для всех в MongoDB с помощью python, но в ответе я получаю null.
{'_id': ObjectId('618af03902cd107477e3f2b9'),
"Time":[1364,1374,1384],
"yaw":[0.15,0.3,0.45],
"pitch":[0.36,0.76,1.08],
"roll":[-0.13,-0.25,-0.35],
"ax":[-0.42,-0.41,-0.41],
"ay":[-0.15,-0.13,-0.1],
"az":[0.9,0.91,1],
"gx":[0,0,0],
"gy":[-0.01,0,-0.01],
"gz":[0.02,0.02,0.02],
"mx":[0.26,0.26,0.26],
"my":[0.01,0.01,0.01],
"mz":[-0.04,-0.04,-0.07]
}
Я хочу усреднить время, рыскание, высоту тона, и у меня есть этот запрос в Python для MongoDB:
@app.route('/sta')
def sta():
docs = db.basetest.aggregate([{"$group": {"_id": '618af03902cd107477e3f2b9', "avgTest" : {"$avg":"Time"}} }])
for document in docs:
return document
Я получаю это возвращение:
{
"_id": "618af03902cd107477e3f2b9",
"avgTest": null
}
Кто-нибудь может помочь?
Комментарии:
1. Вы хотите получить среднее значение всех значений? Или среднее значение по каждому из них?
2. Я хочу, чтобы среднее значение каждого массива было отдельным, время: среднее из 3 значений, рыскание: среднее из 3 значений и так далее. В моем коде я тестирую только один параметр (время), чтобы проверить, работает ли он.
3. $avg можно использовать с массивами, также вам не нужна группа, см. Это
Ответ №1:
Более динамичным решением было бы следующее:
db.collection.aggregate([
{
$project: {
data: {
$filter: {
input: { $objectToArray: "$ROOT" },
cond: { $ne: ["$this.k", "_id"] }
}
}
}
},
{ $set: { data: { $map: { input: "$data", in: { k: "$this.k", v: { $avg: "$this.v" } } } } } },
{ $replaceWith: { $mergeObjects: [{ _id: "$_id" }, { $arrayToObject: "$data" }] } }
])
Если вы хотите получить среднее значение по всем документам, то это становится более сложным. Я нашел это решение, может быть, есть более короткое / лучшее:
db.collection.aggregate([
{ $group: { _id: null, data: { $push: { $objectToArray: "$ROOT" } } } },
{
$set: {
data: {
$reduce: {
input: "$data",
initialValue: [],
in: { $concatArrays: ["$value", "$this"] }
}
}
}
},
{ $unwind: "$data" },
{ $group: { _id: "$data.k", v: { $push: "$data.v" } } },
{ $match: { _id: { $ne: "_id" } } },
{
$set: {
v: {
$reduce: {
input: "$v",
initialValue: [],
in: { $concatArrays: ["$value", "$this"] }
}
}
}
},
{ $set: { _id: "$REMOVE", k: "$_id", v: { $avg: "$v" } } },
{ $group: { _id: null, data: { $push: "$ROOT" } } },
{ $replaceWith: { $arrayToObject: "$data" } }
])
Это другое решение, оно может иметь лучшую производительность:
db.collection.aggregate([
{ $unset: "_id" },
{ $group: { _id: null, data: { $push: { $objectToArray: "$ROOT" } } } },
{
$set: {
data: {
$reduce: {
input: "$data",
initialValue: [],
in: { $concatArrays: ["$value", "$this"] }
}
}
}
},
{
$set: {
data: {
$map: {
input: { $setUnion: "$data.k" },
as: "k",
in: { $filter: { input: "$data", cond: { $eq: ["$this.k", "$k"] } } }
}
}
}
},
{
$set: {
data: {
$map: {
input: "$data",
as: "val",
in: {
k: { $first: "$val.k" },
v: {
$avg: {
$reduce: {
input: "$val.v",
initialValue: [],
in: { $concatArrays: ["$value", "$this"] }
}
}
}
}
}
}
}
},
{ $replaceWith: { $arrayToObject: "$data" } }
])
Комментарии:
1. Это работает в среднем, например, для 10 документов или только для одного документа? Большое спасибо
2. Также для многих документов (я пропустил
{$match: {_id: ObjectId('618af03902cd107477e3f2b9')}}
). Он вычисляет средние значения для каждого документа.3. я хочу рассчитать все среднее значение из 10 одинаковых документов. Большое спасибо
4. Что вы подразумеваете под «10 равными документами»?
5. Затем добавьте
{$limit: 10}
, но результат не определен!
Ответ №2:
Вы можете использовать оператор $avg на $project
этапе (или $set
или $addFields
, если вы предпочитаете) следующим образом:
db.collection.aggregate([
{
"$project": {
"Time": {"$avg": "$Time"},
"yaw": {"$avg": "$yaw"},
"pitch": {"$avg": "$pitch"},
"roll": {"$avg": "$roll"},
"ax": {"$avg": "$ax"},
"ay": {"$avg": "$ay"},
"az": {"$avg": "$az"},
"gx": {"$avg": "$gx"},
"gy": {"$avg": "$gy"},
"gz": {"$avg": "$gz"},
"mx": {"$avg": "$mx"},
"my": {"$avg": "$my"},
"mz": {"$avg": "$mz"}
}
}
])
Пример здесь
Комментарии:
1. спасибо за помощь, это решает мою проблему. еще один вопрос, возможно ли получить среднее значение из 10 документов или только 1?
2. Чтобы получить значение для большего количества документов, которые вам нужно использовать
$group
, а затем$project
этап. Также вы можете использовать$limit
, если вам нужно только предопределенное значение документов.3. я ставлю «$group»:{ «_id»:»$ _id», count : { проект… } но там написано неизвестный групповой оператор ‘$project’
4. Попробуйте выполнить этот запрос