Mongoose - How to query subdocument by property value

I am trying to get an array of unpaid orders. The order subdocument has a property isPaid

that determines whether the order has been paid.

In my opinion, I only want to display orders that have not been paid.

Here is my schematic:

var order = new Schema({
   content: [{
        product: {type: String, required: true},
        quantity: {type: Number},
        vatRate: {type: Number, required: true},
        price: {type: Number}
    }],
    isPaid: {type: Boolean, default: false},
    number: {type: Number}
});

var clientSchema = new Schema({
[...]
information: {
    code: {type: String, required: true},
    name: {type: String, required: true}
},
orders: [order],
[...]
});

      

I started with but no success

clientModel.find(
    {
       "information.code": clientCode, 
       "orders.isPaid": false
    }, function (err, client) { ... });

      

Then I made many attempts with $all

, $elemMatch

without success. In most cases, it will return all orders, paid or unpaid. I do not know why. I need help please :)

+3


source to share


1 answer


One approach you can take is to use an aggregation structure to get the array you want. Consider the following conveyor, in which the first statement is used to filter documents that move to the next stage . This step deconstructs the orders array field from the input documents to output a document for each item. Each output is an input with the array field value replaced by an element. $match

$unwind

The next step uses an operator to then perform additional filtering on the deconstructed subdocuments, which will then be grouped (using ) using an expression and applies an accumulator expression (in the orders subset) to each group that returns the required array. $match

$group

_id

$push

In the end, the pipeline will look like this:



var pipeline = [
    {
        "$match": {
            "information.code": clientCode, 
            "orders.isPaid": false
        }
    },
    { "$unwind": "$orders" },
    {
        "$match": {     
            "orders.isPaid": false
        }
    },
    {
        "$group": {
            "_id": "$_id",
            "orders": {
                "$push": "$orders"
            }
        }
    }
]

clientModel.aggregate(pipeline).exec(function (err, res){
    if (err) return handleError(err);
    console.log(res); // [ { orders: [...] } ]
});

      

Or using the Conveyor Aggregate Builder :

clientModel.aggregate()
    .match({"information.code": clientCode, "orders.isPaid": false})
    .unwind("orders")
    .match({"orders.isPaid": false })
    .group({"_id": "$_id", "orders": { "$push": "$orders" } })
    .select("-_id orders")
    .exec(function (err, res) {
        if (err) return handleError(err);
        console.log(res); // [ { orders: [...] } ]
    });

      

+2


source







All Articles