【问题标题】:Get count of siblings in subdocument with mongodb aggregate query使用 mongodb 聚合查询获取子文档中的兄弟姐妹数
【发布时间】:2015-05-03 13:24:09
【问题描述】:

我有一个带有标签子文档的文档集合。

{
    title:"my title",
    slug:"my-title",
    tags:[
        {tagname:'tag1', id:1},
        {tagname:'tag2', id:2},
        {tagname:'tag3', id:3}]
}
{
    title:"my title2",
    slug:"my-title2",
    tags:[
        {tagname:'tag1', id:1},
        {tagname:'tag2', id:2}]
}
{
    title:"my title3",
    slug:"my-title3",
    tags:[
        {tagname:'tag1', id:1},
        {tagname:'tag3', id:3}]
}
{
    title:"my title4",
    slug:"my-title4",
    tags:[
        {tagname:'tag1', id:1},
        {tagname:'tag2', id:2},
        {tagname:'tag3', id:3}]
}

[...]

使用 $unwind + group count 聚合来获取每个标签的计数非常简单

但是,我想找出一起找到的标签的计数,或者更准确地说,哪个兄弟姐妹最常出现在彼此旁边,按计数排序。我没有找到示例,也无法弄清楚如何在没有多个查询的情况下执行此操作。

理想的最终结果是:

{'tag1':{
    'tag2':3, // tag1 and tag2 were found in a document together 3 times
    'tag3':3, // tag1 and tag3 were found in a document together 3 times
    [...]}}

{'tag2':{
    'tag1':3, // tag2 and tag1 were found in a document together 3 times
    'tag3':2, // tag2 and tag3 were found in a document together 2 times
    [...]}}

{'tag3':{
    'tag1':3, // tag3 and tag1 were found in a document together 3 times
    'tag2':2, // tag3 and tag2 were found in a document together 2 times
    [...]}}

[...]

【问题讨论】:

  • 我认为您的意思是"tags": [ {} ],因为与您键入的内容相比,这将是数组语法,这实际上不是有效的文档结构。您不能使用聚合框架创建任意“键名”。它似乎也不太可能获得您想要的结果(或接近它),但我真的只是在猜测,因为您的问题缺乏可能产生明确预期结果的明确样本。见:How to Create a Minimal, Complete and Verifiable Example
  • 这只是简单的简化,原始文件很大,子文件也很大。
  • 见您更正了数组表示法。不要求您提交整个事情,只是一个样本和一个可以从该样本中的数据实际获得(期望)的结果。它使您的问题比现在更清楚。
  • 是否足够清楚,还是您需要进一步澄清。
  • “根据您提供的单个文档数据样本,我们如何获得您所期望的结果?”我们不可以。因此,我要求您提供足够的文档,以便能够产生您期望的示例输出。

标签: javascript mongodb mongodb-query aggregation-framework


【解决方案1】:

如前所述,让聚合框架从数据中生成任意键名是不可能的。也不可能在单个查询中进行这种分析。

但是有一种通用方法可以在整个集合中针对不确定数量的标签名称执行此操作。本质上,您将需要获取一个不同的“标签”列表,并为每个不同的值处理另一个查询,以获取该标签的“兄弟”和计数。

一般:

// Get a the unique tags
db.collection.aggregate([
    { "$unwind": "$tags" },
    { "$group": {
        "_id": "$tags.tagname"
    }}
]).forEach(function(tag) {
    var tagDoc = { };
    tagDoc[tag._id] = {};

    // Get the siblings count for that tag
    db.collection.aggregate([
        { "$match": { "tags.tagname": tag._id } },
        { "$unwind": "$tags" },
        { "$match": { "tags.tagname": { "$ne": tag._id } } },
        { "$group": {
            "_id": "$tags.tagname",
            "count": { "$sum": 1 }
        }}
    ]).forEach(function(sibling) {
          // Set the value in the master document
          tagDoc[tag._id][sibling._id] = sibling.count;   
    });
    // Just emitting for example purposes in some way
    printjson(tagDoc);
});

聚合框架可以在 MongoDB 2.6 之后的版本中返回游标,因此即使有大量标签,这也可以有效地工作。

这就是您处理此问题的方式,但实际上没有办法在单个查询中发生这种情况。为了更短的运行时间,您可以查看允许多个查询并行运行的框架,或者合并结果或发送到流。

【讨论】:

  • 这与我之前的方法类似,它是一个独特的查询,然后是展开和分组。有没有办法在一个聚合中做到这一点?
  • @tweak2 不,由于这里的答案中已经描述的原因,不可能一次性完成。还要注意的是.distinct() 命令返回一个数组而不是游标的区别,因此您可以获得的结果大小有限制。使用游标和输出流消除了限制。 .distanct() 也不能按照实际“兄弟姐妹”的要求“过滤”数组内容。
猜你喜欢
  • 1970-01-01
  • 2019-08-21
  • 1970-01-01
  • 1970-01-01
  • 2014-09-20
  • 2014-04-23
  • 2012-07-23
  • 2019-05-06
  • 1970-01-01
相关资源
最近更新 更多