使用mongoid计算聚合的数组大小

时间:2017-06-15 11:06:27

标签: ruby-on-rails mongodb mongoid aggregation-framework

我试图将MongoDB shell中的聚合转换为使用Mongoid作为ODM的ruby代码。

我有一些像这样的文件(非常简单的例子):

{
  "name": "Foo",
  "tags": ["tag1", "tag2", "tagN"] 
},
{
  "name": "Bar",
  "tags": ["tagA", "tag2"]
},
...

现在我想获取所有带有名称字段的文档以及每个文档的标签总数。

在MongoDB shell中,我可以使用聚合框架来实现它:

db.documents.aggregate(
  {$project: {name: 1, tags_count: {$size: $tags}}
)

它将返回:

[{"name": "Foo", "tags_count": 3},
{"name": "Bar", "tags_count": 2}]

现在令人沮丧的是,我尝试使用Mongoid作为ODM在rails应用程序中实现相同的查询。

代码看起来像(使用rails控制台):

Document.collection.aggregate(
   [
     {'$project': {name: 1, tags_count: {'$size': '$tags'}}}
   ]
 ).to_a

然后它返回下一个错误:

  

Mongo :: Error :: OperationFailure:$ size的参数必须是一个数组,但类型为:EOO(17124)

我的问题是:如何让Mongoid明白$tags是否参考了正确的字段?或者我在代码中遗漏了什么?

由于

1 个答案:

答案 0 :(得分:2)

看起来有些数据在字段中一直没有数组。为此,您可以使用$ifNull放置一个没有找到空数组的空数组,从而将$size作为0返回:

Document.collection.aggregate(
   [
     {'$project': {name: 1, tags_count: {'$size': { '$ifNull': [ '$tags', [] ] } } }}
   ]
 ).to_a

或者,您可以使用$exists简单地跳过根本不存在字段的位置:

Document.collection.aggregate(
   [
     {'$match': { 'tags_count': { '$exists': true } } },
     {'$project': {name: 1, tags_count: {'$size': '$tags'}}}
   ]
 ).to_a

但当然会从选择中过滤掉那些文件,这可能是也可能不是预期的效果。