Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mongoose Virtuals in MongoDB Aggregate

My Mongoose Schema is as follows:

var DSchema = new mongoose.Schema({
  original_y: {type: Number},,
  new_y: {type: Number},,
  date: {type: Date},
  dummy: [dummyEmbeddedDocuments]
  }, toObject: { virtuals: true }, toJSON: { virtuals: true}
});

DSchema.virtual('dateformatted').get(function () {
 return moment(this.date).format('YYYY-MM-DD HH:mm:ss');
});

module.exports = mongoose.model('D', DSchema);

A document in my schema would be the following:

{
 id:1,
 original_y: 200,
 new_y: 140,
 date: 2015-05-03 00:00:00.000-18:30,
 dummy: [
  {id:1, storage:2, cost: 10},
  {id:2, storage:0, cost: 20},
  {id:3, storage:5, cost: 30},
  ]
}

My Query:

Item.aggregate([
{ 
    "$match": {
        "dummy.storage": {"$gt": 0}
    } 
},
{ 
    "$unwind": "$dummy"
},
{
    "$project": {
        "original_y": 1, 
        "new_y": 1,
        "dateformatted": 1,
        "dummy.id": "$dummy.id",
        "dummy.storage": "$dummy.storage",
        "dummy.cost": "$dummy.cost",
        "dummy.tallyAmount": {
            "$divide": [
                { "$add": ["$new_y","$original_y"] },
                "$dummy.cost"
            ]
        }
    }
},
{
    "$group": {
        "_id": "_$id",
        "original_y": { "$first": "$original_y" },
        "dateformatted": { "$first": "$dateformatted" },
        "new_y": { "$first": "$new_y" },
        "dummy": {
            "$addToSet": "$dummy"
        }
    }        
}
]).exec(callback);

This query however returns the VIRTUAL dateformatted attribute as NULL. Any thoughts as to why this is happening?

like image 569
Rohit Lala Avatar asked May 04 '15 19:05

Rohit Lala


People also ask

What are virtuals in Mongoose?

In Mongoose, a virtual is a property that is not stored in MongoDB. Virtuals are typically used for computed properties on documents.

Can we use populate in aggregate MongoDB?

Short answer: You can't.

What does aggregate return Mongoose?

Mongoose's aggregate() function returns an instance of Mongoose's Aggregate class. Aggregate instances are thenable, so you can use them with await and promise chaining. The Aggregate class also supports a chaining interface for building aggregation pipelines.

What are the differences between using aggregate () and find ()? In MongoDB?

With aggregate + $match, you get a big monolithic BSON containing all matching documents. With find, you get a cursor to all matching documents. Then you can get each document one by one.


1 Answers

A couple notes in the docs touch on why this is so:

  • Arguments are not cast to the model's schema because $project operators allow redefining the "shape" of the documents at any stage of the pipeline, which may leave documents in an incompatible format.
  • The documents returned are plain javascript objects, not mongoose documents (since any shape of document can be returned).

But it goes beyond this because the aggregate operation is performed server-side, where any client-side Mongoose concepts like virtuals do not exist.

The result is that you'll need to include the date field in your $project and $group stages and add your own dateformatted field to the results in code based on the date values.

like image 189
JohnnyHK Avatar answered Sep 22 '22 19:09

JohnnyHK