首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >类过滤器子文档上的Mongodb聚合

类过滤器子文档上的Mongodb聚合
EN

Stack Overflow用户
提问于 2013-06-12 08:19:03
回答 1查看 1.6K关注 0票数 1

首先,为我糟糕的英语感到抱歉。

如果我们在MongoDB中有以下文档,

测试数据

代码语言:javascript
复制
{id:1, filter:{f1:'v1-1', f2:'v2-1', f3:['v3-1', 'v3-3']}}
{id:2, filter:{f1:'v1-1', f2:'v2-2', f3:['v3-2', 'v3-3']}}
{id:3, filter:{f1:'v1-1', f2:'v2-2', f3:['v3-1', 'v3-3']}}

准备集合

代码语言:javascript
复制
db.test.drop()
db.test.insert({id:1, filter:{f1:'v1-1', f2:'v2-1', f3:['v3-1', 'v3-3']}})
db.test.insert({id:2, filter:{f1:'v1-1', f2:'v2-2', f3:['v3-2', 'v3-3']}})
db.test.insert({id:3, filter:{f1:'v1-1', f2:'v2-2', f3:['v3-1', 'v3-3']}})

您可以将filter字段视为在许多购物站点上使用的过滤器功能,例如,它们将告诉您站点上有多少LED电视和多少LCD电视。

我想使用MongoDB计算每个过滤器选项(包括数组字段中的每个项)的文档数,预期结果如下所示。

预期结果

代码语言:javascript
复制
[
    {
       _id : { key: 'f1', value: 'v1-1' }, count: 3
    },
    {
       _id : { key: 'f2', value: 'v2-1' }, count: 1
    },
    {
       _id : { key: 'f2', value: 'v2-2' }, count: 2
    },
    {
       _id : { key: 'f3', value: 'v3-1' }, count: 2
    },
    {
       _id : { key: 'f3', value: 'v3-2' }, count: 1
    },
    {
       _id : { key: 'f3', value: 'v3-3' }, count: 3
    }
]

使用map/reduce很容易得到结果,

映射/约简解决方案

代码语言:javascript
复制
map = function () { 
    for (k in this.filter) { 
        if (this.filter[k] instanceof Array) {
            for (j in this.filter[k]) {
                emit( { key: k, value: this.filter[k][j]}, 1 ); 
            }
        } else {
            emit( { key: k, value: this.filter[k]}, 1 ); 
        }
    } 
}

reduce = function (k, values) { 
    result = 0;  
    values.forEach( function(v) { result += v; } ); 
    return result; 
}

db.test.mapReduce(map, reduce, {out:{inline:1}})

但由于map/reduce的性能问题,不能用于实时查询。如果添加一些查询条件,则结果集可能会更改,因此无法将map/还原结果保存到另一个集合中进行实时查询。

我可以使用聚合框架来计算一个过滤器的计数,

只针对一个过滤器的聚合解决方案

代码语言:javascript
复制
db.test.aggregate(
{$project: {"filter.f2":1, "_id":0}},
{$group:   {"_id": {"key": {$ifNull: [null, "f2"]}, "value":"$filter.f2"}, "count" : {$sum: 1}}}
)

[
    {
        "_id" : { "key" : "f2", "value" : "v2-2" }, "count" : 2
    },
    {
        "_id" : { "key" : "f2", "value" : "v2-1" }, "count" : 1
    }
]

但我不知道怎么做所有的过滤器选项。有什么想法吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-06-12 19:47:13

如果您将数据结构更改为类似的内容,请注意,所有值都是数组,甚至是具有单个值的数组:

代码语言:javascript
复制
{
  _id: 1,
  filters: [{
    key: 'f1',
    values: ['v1-1']
  },{
    key: 'f2',
    values: ['v2-1']
  },{
    key: 'f3',
    values: ['v3-1', 'v3-3']
  }]
}
{
  _id: 2,
  filters: [{
    key: 'f1',
    values: ['v1-1']
  },{
    key: 'f2',
    values: ['v2-2']
  },{
    key: 'f3',
    values: ['v3-2', 'v3-3']
  }]
}
{
  _id: 3,
  filters: [{
    key: 'f1',
    values: ['v1-1']
  },{
    key: 'f2',
    values: ['v2-2']
  },{
    key: 'f3',
    values: ['v3-1', 'v3-3']
  }]
}

您可以执行这样的聚合函数:

代码语言:javascript
复制
db.test.aggregate({
  $unwind: "$filters"
},{
  $project: {
    _id: 1,
    key: "$filters.key",
    values: "$filters.values"
  }
},{
  $unwind: "$values"
},{
  $group: {
    _id: {
      $concat: ["$key","|","$values"]
    },
    count: { $sum: 1 }
  }
})

如果你愿意的话,你可以跳过这个项目的步骤,我只是把它放在里面作为一个精确的步骤。无论如何,你都需要两次放松。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/17060786

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档