如何使用MongoDB聚合管道按所有可能的组合进行分组

hrysbysz  于 2023-06-29  发布在  Go
关注(0)|答案(1)|浏览(105)

使用MongoDB版本4.4.22假设我有这个文档:

[
    {
            _id: ObjectId("6481b9762f11910c77d977ae")
            hints : [
                {
                        creatorId : "093c90be-8f19-45de-89ab-20070ef6d3f5",
                        textValue: "hint1"
                },
                {
                        creatorId : "093c90be-8f19-45de-89ab-20070ef6d3f5",
                        textValue: "hint2"
                },
                {
                        creatorId : "575b9c75-c89d-4505-aec5-b001d8836845",
                        textValue: "hint3"
                },
                {
                        creatorId : "575b9c75-c89d-4505-aec5-b001d8836845",
                        textValue: "hint4"
                }
            ]
    },
    {
            _id: ObjectId("6168b9751000006e9d436bd1")
            hints : [
                {
                        creatorId : "093c90be-8f19-45de-89ab-20070ef6d3f5",
                        textValue: "hint1"
                },
                {
                        creatorId : "575b9c75-c89d-4505-aec5-b001d8836845",
                        textValue: "hint3"
                },
            ]
    }
]

每条记录都有hints数组,它由具有creatorIdtextValue的文档组成,我想为每个可能的提示组合计算有多少记录包含这些提示。我想要计数的有效组合是不具有相同creatorId出现两次的组合。为了示例起见,让我们猜测每个记录至少有一个来自每个可能的创建者的提示(因此不需要支持部分组合)。重要提示:两个具有相同textValue但创建者不同的提示是两个不同的提示!有没有一种方法可以只使用聚合管道来获得结果?(不涉及代码)
对于给定的示例,这是预期的结果(_id用于$group场景):

[
    {
        _id: [
            {
                        creatorId : "093c90be-8f19-45de-89ab-20070ef6d3f5",
                        textValue: "hint1"
                },
                {
                        creatorId : "575b9c75-c89d-4505-aec5-b001d8836845",
                        textValue: "hint3"
                },
        ],
        count: 2
    },
    {
        _id: [
            {
                        creatorId : "093c90be-8f19-45de-89ab-20070ef6d3f5",
                        textValue: "hint1"
                },
                {
                        creatorId : "575b9c75-c89d-4505-aec5-b001d8836845",
                        textValue: "hint4"
                }
        ],
        count: 1
    },
    {
        _id: [
                {
                        creatorId : "093c90be-8f19-45de-89ab-20070ef6d3f5",
                        textValue: "hint2"
                },
                {
                        creatorId : "575b9c75-c89d-4505-aec5-b001d8836845",
                        textValue: "hint3"
                },
        ],
        count: 1
    },
    {
        _id: [
                {
                        creatorId : "093c90be-8f19-45de-89ab-20070ef6d3f5",
                        textValue: "hint2"
                },
                {
                        creatorId : "575b9c75-c89d-4505-aec5-b001d8836845",
                        textValue: "hint4"
                }
        ],
        count: 1
    }
]

我尝试了许多管道,但总是停留在一个场景中,当一个记录包含来自同一个创建者的多个提示时。很高兴帮助和想法!

5w9g7ksd

5w9g7ksd1#

最终我找到了一个解决方案(我不认为这是最佳的,但它的工作):
我可以使用$function step来编写一个JS代码,它在hints数组上运行,以生成我想要的所有组合:

function (hints) {
  if(!hints || hints.length == 0) return [[]]
  function getPowerSet(hints) {
    const powerSet = [[]]; // Initialize with an empty set
    for (const hint of hints) {
      const currentSetLength = powerSet.length;
      for (let i = 0; i < currentSetLength; i++) {
        const subset = [...powerSet[i], hint];
        powerSet.push(subset);
      }
    }
    return powerSet;
  }
  
  function filterArraysByHintUniqueness(array) {
      creatorIds = array.map(l => l.creatorId)
      const uniqueValues = new Set(creatorIds);
      return array.length === uniqueValues.size;
  }
  
  return getPowerSet(hints)
   .filter(filterArraysByHintUniqueness)
   .filter((array) => array.length == numOfCreators)
   .sort((array) => array.sort((a, b) => a.creatorId.localeCompare(b.creatorId)))
}

numOfCreators是已知的,我们可以动态地使用它。我使用的步骤如下:

{
  "$addFields" : {
    "possibleCombinations" : {
      "$function" : {
        "body" : <The JS code mentioned above>,
        "args" : ["$hints"],
        "lang" : "js"
      }
    }
  }
}

之后,在possibleCombinations字段上执行一个简单的$unwind阶段和一个简单的$group阶段。

相关问题