Prakash Kumar Prakash Kumar - 24 days ago 6
Node.js Question

Use aggregation to match one field of the document with the array size of that same document

I am using nodejs with mongodb and i have below document in my database

{
arr: ["abc", "def", "ghi", "jkl"],
ctr: 0
},
{
arr: ["aeiop"],
ctr: 0
}


Now i want to write an aggregation query if ctr is less than size of array arr then i want to return that document.

Below is the query i wrote

areamodel.aggregate(
{ $match : { ctr:{$lt : {$size: "$arr"} } },
{$sort:{time_posted: -1}},
function(err, docs) {
if (err) {
console.log(err);
} else {

}
}
);


But i am not getting anything in response because none of query matches.

Can anyone please tell me in mognodb how to perform aggregation query.

Answer

Consider manipulating the comparison operators within the $project pipeline and a subsequent $match pipeline to filter documents based on the additional field with the $cmp expression:

couponmodel.aggregate([
    {
        "$project": {
            "arr": 1,
            "ctr": 1,
            "time_posted": 1,
            "comparer": { 
                "$cmp": [ "$ctr", { "$size": "$arr" } ]
            }
        }
    },
    { "$match": { "comparer": -1 } }
    { "$sort": { "time_posted": -1 } },
], function(err, docs) {
    if (err) {
        console.log(err);
    } else {
        console.log(docs);
    }
});

The only drawback with this approach is that you need to project the fields you want as well as creating an additional field that you may not need.


Another option which circumvents the above is using a single pipeline with $redact operator which incorporates the functionality of $project and $match as above and returns all documents which match a specified condition using $$KEEP system variable and discards those that don't match using the $$PRUNE system variable. Keep in mind this operator does a collection scan so the first pipeline option may be optimal given the appropriate indexing techniques:

couponmodel.aggregate([
    {
        "$redact": {
            "$cond": [
                { 
                    "$eq": [
                        { "$cmp": [ "$ctr", { "$size": "$arr" } ] }, 
                        -1
                    ]
                }, 
                "$$KEEP", 
                "$$PRUNE"
            ]
        }
    },
    { "$sort": { "time_posted": -1 } },
], function(err, docs) {
    if (err) {
        console.log(err);
    } else {
        console.log(docs);
    }
});