Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to have an auto calculated attribute in mongoose schema

suppose I have following mongoose schema in Node.js

var schema = new mongoose.Schema({
    views:Number,
    clicks:Number,
    ctr:Number
})

In which I want that CTR attribute should be automatically calculated by a formula based on values of other attributes, i.e lets say

ctr = clicks / views

I don't want to have CTR as a virtual field because based on the value of CTR I will sort all documents of my collection and apparently sorting is not possible based on virtual fields. So I was wondering if there is any way to have calculated attributes in mongoose schema which gets automatically updated on update of any of the dependent attribute/field

like image 762
Point Networks Avatar asked May 18 '17 09:05

Point Networks


People also ask

How do I set the default schema in mongoose?

You can also set the default schema option to a function. Mongoose will execute that function and use the return value as the default. const schema = new mongoose.Schema ( { views: { type: Number }, clicks: { type: Number }, ctr: { type: Number, default: function () { return this.clicks / this.views } } })

How to join the documents when querying for posts in mongoose?

As you can see, the we're using the populate function of mongoose to join the documents when querying for Posts. The first call to populate joins the Users for the postedBy property of the posts whereas the second one joins the Users for the comments. In contrast, the query result is a full document containing all User references for the Posts.

Can I reference other documents by ObjectIDs in MongoDB?

When using a NoSQL database like MongoDb, most of the time you'll have documents that contain all properties by itself. But there are also scenarios where you might encounter the need for a more relational approach and need to reference other documents by the ObjectIds.


3 Answers

I want that CTR attribute should be automatically calculated by a formula based on values of other attributes

From the Mongoose docs [emphasis added]:

You can also set the default schema option to a function. Mongoose will execute that function and use the return value as the default.

Therefore, your example could be rewritten as:

const schema = new mongoose.Schema({
  views: {
    type: Number
  },
  clicks: {
    type: Number
  },
  ctr: {
    type: Number,
    default: function() {
      return this.clicks / this.views
    }
  }
})

So I was wondering if there is any way to have calculated attributes in mongoose schema which gets automatically updated on update of any of the dependent attribute/field

If I understand correctly, note the section in the docs on the setDefaultsOnInsert option. This may be of relevance when recalculating the default upon update.

like image 116
Jack Pendleton Avatar answered Sep 21 '22 13:09

Jack Pendleton


You can use for it virtual field:

var schema = new mongoose.Schema({
    views:Number,
    clicks:Number
})

schema.virtual('ctr')
  .get(function() {
    return this.clicks / this.views;
  });
like image 43
Sergaros Avatar answered Sep 20 '22 13:09

Sergaros


You can do anything, but don't forget about that that difficult thing slower your server.

In my case for calculating age user I do that.

const mongoose = require( 'mongoose' );
const Schema = mongoose.Schema;

    const userSchema = new Schema( {

      born: {
        type: String,
        get: a => {
          let date = new Date(a);
          let today = new Date();
          let timeDiff = today.getTime() - date.getTime();
          let age = Math.floor( timeDiff / ( 1000 * 3600 * 24 ) / 365 );
          return age;
        },
        set: age => age,
        alias: 'age',
      },
    } 

);

module.exports = mongoose.model( 'User', userSchema );

And Mongoose Documantation

like image 27
Vladislav Hirsa Avatar answered Sep 19 '22 13:09

Vladislav Hirsa