使用pymongo根据一个值查询两个字段的总和
Posted
技术标签:
【中文标题】使用pymongo根据一个值查询两个字段的总和【英文标题】:Query Sum of two fields based on a value using pymongo 【发布时间】:2022-01-15 07:25:10 【问题描述】:基本上,我有一个带有嵌套对象数组的对象数组。我想根据"userID"
和"flashcardReversed.value" + "flashcardReversed.count"
之和查询数据。
用户将提供所需的用户 ID 和(值 + 计数)值。
这是我的数据:
[
"_id": "608642db80a36336946620aa",
"userID": "user1",
"title": "title2",
"flashcardReversed": [
"_id": "608d5b290e635ece6828141X",
"front": "2front",
"back": "2back",
"value": 1,
"count": 2
,
"_id": "608t5b290e635ece6828141Y",
"front": "2frontReversed",
"back": "2backReversed",
"value": 2,
"count": 3
,
"_id": "608a5b31a3f9806de253726X",
"front": "2front2",
"back": "2back2",
"value": 3,
"count": 4
,
"_id": "608a5b31a3f9806de253726Y",
"front": "2frontReversed2",
"back": "2backReversed2",
"value": 4,
"count": 5
]
,
"_id": "608642db80a36336946620aa",
"userID": "user1",
"title": "title3",
"flashcardReversed": [
"_id": "608d5b290e635ece6828142X",
"front": "2front",
"back": "2back",
"value": 12,
"count": 6
,
"_id": "608t5b290e635ece6828143Y",
"front": "2frontReversed",
"back": "2backReversed",
"value": 21,
"count": 7
,
"_id": "608a5b31a3f9806de253727X",
"front": "2front2",
"back": "2back2",
"value": 34,
"count": 8
,
"_id": "608a5b31a3f9806de253729Y",
"front": "2frontReversed2",
"back": "2backReversed2",
"value": 42,
"count": 9
]
,
"_id": "608642db80a36336946620aa",
"userID": "user2",
"title": "title4",
"flashcardReversed": [
"_id": "608d5b290e635ece6828131X",
"front": "2front",
"back": "2back",
"value": 41,
"count": 10
,
"_id": "608t5b290e635ece6828161Y",
"front": "2frontReversed",
"back": "2backReversed",
"value": 54,
"count": 11
,
"_id": "608a5b31a3f9806de253526X",
"front": "2front2",
"back": "2back2",
"value": 63,
"count": 12
,
"_id": "608a5b31a3f9806de253326Y",
"front": "2frontReversed2",
"back": "2backReversed2",
"value": 29,
"count": 13
]
]
例如查询应该是这样的:
"userID": "$eq": provided_user_id
"flashcardReversed.value" + "flashcardReversed.count": "$eq": provided_value_plus_count
是否可以使用 pymongo 来实现这一点?
【问题讨论】:
输出已损坏(字段后缺少一些逗号)但_id
对于所有三个文档都是相同的——假设它们应该是集合中的三个独立文档而不是数组1 个文档中的 3 个项目。另外:您是要匹配为用户找到的所有文档的总和,还是每个文档(您的数据表明 userID 可以显示在多个文档中)。请澄清一下。
json 无效,如果您可以使用 this 之类的东西来检查它
【参考方案1】:
假设这里的唯一性是userID+title
,并且我们希望在flashcardReversed
字段和多个title
之间进行聚合,即为用户获取一个数字,那么这是一个解决方案。
var targetUser = "user1";
var targetAmt = 163;
c = db.foo.aggregate([
$match: "userID": targetUser // will fetch one OR MORE records...
,$addFields:
X: $reduce:
input: "$flashcardReversed",
initialValue: 0,
// $$value is the running result of the reduce operation ($add)
// $$this is the current object from the array; it just so
// happens that a field in your object is named "value" so
// do not confuse the two. The expression below translates
// to: n = n + oneitem.value + oneitem.count
in:$add: [ "$$value", "$$this.value", "$$this.count" ]
// Now, add up X over multiple docs. We can group by null because we
// know ONLY docs where userID = targetUser are coming through:
,$group: _id: null, n: $sum: "$X"
// ...and match against input:
,$match: n: targetAmt
]);
上述解决方案演示了单独的 $reduce
和 $group
行为,但这些行为可以组合使用。另外,让我们探讨一下要为目标数量获取多个用户需要做什么:
var targetUser = ["user1","user2"];
var targetAmt = 163;
c = db.foo.aggregate([
$match: "userID": $in: targetUser
// Combine the $group and $reduce together. Saves a stage! Also, since
// more than one userID can come through, we must change _id to group
// by $userID instead of null:
,$group: _id: "$userID", n: $sum: $reduce:
input: "$flashcardReversed",
initialValue: 0,
in:$add: [ "$$value", "$$this.value", "$$this.count" ]
// Probably want to use >= or <= instead of exact match sometimes
// so here is an example of that:
,$match: $expr: $gte: ["$n", targetAmt]
]);
"_id" : "user1", "n" : 163
"_id" : "user2", "n" : 233
【讨论】:
【参考方案2】:查询
匹配用户 ID 过滤数组并只保留(= (+ value count) 3)
的成员
您可以将 3 替换为变量或任何数字
如果过滤后数组为空,则拒绝文档
在最终结果中,我们只在数组中保留通过的那些,并且只保留至少有 1 个通过的文档
*不确定你是否想要这个
Test code here
aggregate(
["$match": "userID": "$eq": "user1",
"$set":
"flashcardReversed":
"$filter":
"input": "$flashcardReversed",
"cond":
"$eq": ["$add": ["$$this.value", "$$this.count"], 3],
"$match": "$expr": "$ne": ["$flashcardReversed", []]])
【讨论】:
嗨@Takis_,是的,该解决方案工作正常。但是,它只从其中一个对象返回。假设有两个 userID 为 user1 的对象,它们都有一些 flashcardReversed 对象,其值和计数总和为 3。您的查询仅从其中一个对象返回 flashcardReversed 对象。这里cmql.org/play/?q=1639239808949,你可以看到我想说的。 我明白了你的意思,但是在你的示例数据中你有相同的_id
,这在 MongoDB 中不起作用(只插入了 1 个),我在修复它后重新运行它,并且我拿了this,看起来不错,有两个对象,如果你不喜欢这个,你可以$unwind
还有数组,如果你被卡住发送预期的输出,所以我们知道你到底需要什么
谢谢@Takis_ :)以上是关于使用pymongo根据一个值查询两个字段的总和的主要内容,如果未能解决你的问题,请参考以下文章