1

I'm trying to translate aggregation from the MongoDB shell to ruby code that uses Mongoid as ODM.

I have some documents like this (very simplified example):

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

Now I'd like to get all documents with the name field and the total number of tags for each.

In the MongoDB shell I can achieve it using aggregation framework like this:

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

And it will return:

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

Now the frustrating part, I'm trying to implement the same query inside a rails app using Mongoid as ODM.

The code looks like (using rails console):

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

And it returns the next error:

Mongo::Error::OperationFailure: The argument to $size must be an Array, but was of type: EOO (17124)

My question is: How can I make Mongoid understand that $tags makes reference to the correct field? Or what I'm missing from the code?

Thanks

1
  • 1
    It would appear that your data does not actually contain arrays, or perhaps not consistently. The same statement should fail in the shell on the same data for the same reason. Commented Jun 15, 2017 at 11:07

1 Answer 1

2

It looks like there is data which does not consistently have an array in the field. For this you can use $ifNull to place an empty array where none is found and thus return the $size as 0:

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

Alternately you could simply skip where the field is not present at all using $exists:

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

But of course that will filter those documents from the selection, which may or may not be the desired effect.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.