我有这样的文档结构:
[
{
"country": "UK",
"shops": [
{"city": "London", "fruits": ["banana", "apple"]},
{"city": "Birmingham", "fruits": ["banana", "pineapple"]},
],
},
{
"country": "DE",
"shops": [
{"city": "Munich", "fruits": ["banana", "strawberry"]},
{"city": "Berlin", "fruits": ["kiwi", "pineapple"]},
],
},
]
在我的Python脚本中,我有一个字典将每个水果映射到一个类别值:
categories = {
1: ["apple"],
2: ["banana", "kiwi"],
3: ["pineapple", "strawberry"]
}
期望的输出:
现在我想使用 mongo 聚合框架,对于每个文档,根据类别映射从商店子文档中找到的最大值投影出 max_category 。
[
{
"country": "UK",
"shops": [
{"city": "London", "fruits": ["banana", "apple"]},
{"city": "Birmingham", "fruits": ["banana", "pineapple"]},
],
"max_category": 3
},
{
"country": "DE",
"shops": [
{"city": "Munich", "fruits": ["banana", "apple"]},
{"city": "Berlin", "fruits": ["kiwi", "apple"]},
],
"max_category": 2
},
]
感谢您的帮助!
您的类别字典不适合 mongo,因为 mongo 要求对象具有字符串类型的键。您可以将字典转换为以下形式以便于处理:
[
{
category: 1,
fruits: [
"apple"
]
},
{
category: 2,
fruits: [
"banana",
"kiwi"
]
},
{
category: 3,
fruits: [
"pineapple",
"strawberry"
]
}
]
在聚合管道中,通过
$reduce
迭代整理的类别数组,以有条件地更新累加器以获得最大匹配类别。
db.collection.aggregate([
{
"$unwind": "$shops"
},
{
"$set": {
"max_category": {
"$reduce": {
"input": [
{
category: 1,
fruits: [
"apple"
]
},
{
category: 2,
fruits: [
"banana",
"kiwi"
]
},
{
category: 3,
fruits: [
"pineapple",
"strawberry"
]
}
],
"initialValue": null,
"in": {
"$cond": {
"if": {
$and: [
{
$gt: [
"$$this.category",
"$$value"
]
},
{
$gt: [
{
$size: {
"$setIntersection": [
"$$this.fruits",
"$shops.fruits"
]
}
},
0
]
}
]
},
"then": "$$this.category",
"else": "$$value"
}
}
}
}
}
},
{
"$group": {
"_id": "$_id",
"country": {
$first: "$country"
},
"max_category": {
$max: "$max_category"
},
"shops": {
"$push": "$shops"
}
}
}
])
一个选项是:
db.collection.aggregate([
{
$set: {
max_category: {
$max: {
$reduce: {
input: "$shops",
initialValue: 0,
in: {
$max: [
"$$value",
{
$map: {
input: "$$this.fruits",
as: "f",
in: {
$toInt: {
$getField: {
field: "k",
input: {
$first: {
$filter: {
input: {
$objectToArray: categories
},
as: "val",
cond: {
$in: [
"$$f",
"$$val.v"
]
}
}
}
}
}
}
}
}
}
]
}
}
}
}
}
}
])