Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MongoDB count objects inside objects

i want to know how many elements there are inside objects.

My collections is the following:

{"_id": 'xxx', 
 "comments":{
       "_id_ab6666djdkjd": { 
           "text": "my text"
        },
        "_id_ab6dee": { 
           "text": "my text2"
        }
  }
},
{"_id": 'xxx', 
 "comments":{
       "_id_ab6666dddjdkjd": { 
           "text": "my text"
        }
     }
}

I want to count comments in all documents? I know that is best practise use array in comments but i can't change the schema design.

Best, Lorenzo

like image 261
JBerta93 Avatar asked Sep 17 '25 00:09

JBerta93


1 Answers

Go you your boss and tell them I told them to "Change the Design". Here's the post you should them with me telling them.

The design is horrible and you cannot work on it without processing with code, either on the client or server. On the server that means JavaScript interpretation, in which both the required processing and lack of being able to use better in-build features of MongoDB.

Ideally you should have documents that look like this:

{ 
    "comments":[
       { "_id": "ab6666djdkjd", "text": "my text" }
       { "_id": "ab6dee", "text": "my text2" }
    ],
    "commentCount": 2
},
{
    "comments":{
       { "_id": "ab6666dddjdkjd", "text": "my text" }
    ],
    "commentCount": 1
}

So not only structured as an array but also keeping the "length" of the array, which is easy to do using the $inc operator along with $push and $pull operations.

Your most simple query then becomes this:

db.collection.aggregate([
    { "$group": {
        "_id": null,
        "count": { "$sum": "$commentCount" }
    }}
])

So without a structure to support it you are stuck with running a much slower processor with mapReduce:

db.collection.mapReduce(
    function() {
        emit( null, Object.keys(this.comments).length );
    },
    function(key,values) {
        return Array.sum(values);
    },
    {
        "out": { "inline": 1 }
    }
)

That will sum all the comments in all documents in the collection on your existing structure.

The two things to consider is you are essentially placing "data" within the values of "keys" in this design and creating document paths that are notoriously difficult to "query". When data is present in the key it cannot be indexed, which is going to lead to poor performance as your application usage grows.

The other consideration is that you need "code" to process most of your inquiry needs either client or server side, and in most cases standard query operators or aggregation built-in's will do this much better.

So you can use code as has been shown but really make the change now, because you are going to have to sooner or later as everything in the application slows down.

like image 182
Neil Lunn Avatar answered Sep 19 '25 17:09

Neil Lunn