1

I am new to MongoDB and I want to push an object into array in mongo query.

Here is my code

var array = [
    {
        "heading": "Fruits",
        "contents": []
    },
    {
        "heading": "Vegetables",
        "contents": []
    }
];
var mongoquery = { "category.title": "home" };

for(var i=0; i<array.length; i++){
    for(var j=0; j<array[i].contents.length; j++ ){
        Collection.find(mongoquery).count({}, function(err, count){
            var resultantCount = count;
            array[i].contents.push({
                name: 'Apple',
                count: count
            });
        });
    }
}

While running the above query in my project server side controller, I got an error. I tried to return the count from the query but that is also throwing an error. Now I want to push the object in mongodb query. How do I go about this?

Expected Output

array = [
    {
        "heading": "Fruits",
        "contents": [
            { "name": "Apple", "count": 12 }
        ]
    },
    {
        "heading": "Vegetables",
        "contents": [
            { "name": "Tomato", "count": 18 }
        ]
    }
];
7
  • You use sync and async code together. This will not work. You need to change your for loops to became promises or use async library to iterate over array and only then query and return results. Btw. errors that you see also would be helpful. Commented Oct 28, 2016 at 10:03
  • Thanks for reply,can you please explain me with code @MykolaBorysyuk Commented Oct 28, 2016 at 10:08
  • Are you running this directly in Mongo shell or you are using a driver to do the operation? What is it that you want to achieve, do you want to update an existing document in mongo with the some counts? Can you edit your question with some sample documents and the expected output or desired result? Commented Oct 28, 2016 at 10:13
  • i edited the code and expected output also @chridam Commented Oct 28, 2016 at 10:21
  • Thanks for providing the expected output. Can you also update your question to show some sample documents from the query db.collection.find({ "category.title": "home" })? To provide a detailed answer, we would like to know the input as I believe this is just an aggregation operation where you want to output the counts from a field. Commented Oct 28, 2016 at 10:22

2 Answers 2

1

You using sync and async code together which will not work.

Check this to have more understanding.

https://blog.risingstack.com/node-hero-async-programming-in-node-js/

Also if you want to fix your code i suggest checking this library http://caolan.github.io/async/docs.html#each

With that library to fix your code you just need to

async.each(array, function(value, done){
   //now query mongoDB and write result
   Collection.find(mongoquery).count({}, function(err, count){
        if (err) {return done(err);}
        //as we reference to array type this will modify original array so we can just push into contents
        value.contents.push({
            name: 'Apple',
            count: count
        });
        //callback function when all done. Go to next iteration
        done();
    });
}, function(err){
    if(err) {console.log(err);}
   //final callback here after all iterations done.
   console.log(array);
});

Hope this helps.

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

2 Comments

it is showing an error "async" is not defined @Mykola Borysyuk
You need to install it.npm i async --save
1

Since there's reluctance to show some sample documents in your collection, I've made some underlying assumptions on the structure of the documents in your collection based on the array in question.

Suppose your collection is composed of documents of this nature:

{        
    "category": {
        "title": "home",
        "name": "Fruits"
    },
    "name": "Apple"
},
{        
    "category": {
        "title": "home",
        "name": "Fruits"
    },
    "name": "Orange"
},
{        
    "category": {
        "title": "home",
        "name": "Vegetables"
    },
    "name": "Peas"
}

In order to get the desired result, you need to run an aggregation operation which is very efficient since it uses the native operators in MongoDB rather than doing async calls in a loop which suffers from performance issues.

Consider running the following pipeline:

var pipeline = [
    { "$match": { "category.title": "home" } },
    {
        "$group": {
            "_id": {
                "category": "$category.name",
                "name": "$name"
            },
            "count": { "$sum": 1 }
        }
    },
    {
        "$group": {
            "_id": "$_id.category",
            "contents": {
                "$push": {
                    "name": "$_id.name",
                    "count": "$count"
                }
            }
        }
    },
    {
        "$project": {
            "_id": 0,
            "heading": "$_id",
            "contents": 1
        }
    }
];

Collection.aggregate(pipeline, function(err, result) {
    console.log(JSON.stringify(result, null, 4));
});

Running the above aggregation operation on the assumed sample documents would yield the following result:

Sample Output

[
    {
        "heading": "Fruits",
        "contents": [
            { "name": "Apple", "count": 1 },
            { "name": "Orange", "count": 1 }
        ]
    },
    {
        "heading": "Vegetables",
        "contents": [
            { "name": "Peas", "count": 1 }
        ]
    }
]

UPDATE

From the comments trail, if you are using the collection from your previous question with the sample documents

/* 1 */
{
    "_id" : ObjectId("58133a40c23d8b16b062e86a"),
    "name" : "Tomatos",
    "array" : [ 
        {
            "title" : "Vegetables"
        }
    ],
    "description" : "Vegitables are good to health"
}

/* 2 */
{
    "_id" : ObjectId("58133a40c23d8b16b062e86b"),
    "name" : "Apples",
    "array" : [ 
        {
            "title" : "Fruits"
        }
    ],
    "description" : "Fruits are good to health, vegitables are also good to health"
}

/* 3 */
{
    "_id" : ObjectId("58133a40c23d8b16b062e86c"),
    "name" : "Apples",
    "array" : [ 
        {
            "title" : "Vegetables-home-made"
        }
    ],
    "description" : "Fruits are good to health, vegitables are also good to health"
}

then consider running the following pipeline to get the desired results:

Collection.aggregate([
    { "$unwind": "$array" },
    {
        "$group": {
            "_id": {
                "category": "$array.title",
                "name": "$name"
            },
            "count": { "$sum": 1 }
        }
    },
    {
        "$group": {
            "_id": "$_id.category",
            "contents": {
                "$push": {
                    "name": "$_id.name",
                    "count": "$count"
                }
            }
        }
    },
    {
        "$project": {
            "_id": 0,
            "heading": "$_id",
            "contents": 1
        }
    }
], function(err, result) {
    console.log(JSON.stringify(result, null, 4));
});

Sample Output

/* 1 */
{
    "contents" : [ 
        {
            "name" : "Apples",
            "count" : 1
        }
    ],
    "heading" : "Vegetables-home-made"
}

/* 2 */
{
    "contents" : [ 
        {
            "name" : "Apples",
            "count" : 1
        }
    ],
    "heading" : "Fruits"
}

/* 3 */
{
    "contents" : [ 
        {
            "name" : "Tomatos",
            "count" : 1
        }
    ],
    "heading" : "Vegetables"
}

5 Comments

my collection is like this {"category":[{"title":"home","name":"raj"}]},{"category":[{"title":"home","name":"midhun"}]},{"category":[{"title":"residence",,"name":"john"}]} @chridam
Seeing that you created a similar question here stackoverflow.com/questions/39996979/…, how is this connected to the "vegetables" and "fruits" query?
yeah exactly that is my collection @chridam
So are you saying you have two collections: one with the documents { "_id": objectId(23651478), "name":"Tomatos" "array":[ {"title":"Vegetables"} ] "description":"Vegitables are good to health" } and another with {"category":[{"title":"home","name":"raj"}]}? How are these connected? Or is it one collection? Please be specific in your question.
no i have only one collection only, i have created an assumption example for this question actually my collection is first one i.e, in the link you provided @ chridam

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.