Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

get virtual attribute for each nested object in an array of objects?

So I know how to get a single virtual attribute, as stated in the Mongoose docs:

PersonSchema
 .virtual('name.full')
 .get(function () {
   return this.name.first + ' ' + this.name.last;
});

But what if my schema is:

var PersonSchema = new Schema({
    name: {
      first: String
    , last: String
    },

    arrayAttr: [{
      attr1: String,
      attr2: String
    }]
})

And I want to add a virtual attribute for each nested object in arrayAttr:

PersonSchema.virtual('arrayAttr.full').get(function(){
    return attr1+'.'+attr2;
});

Lemme know if I missed something here.

like image 986
daedelus_j Avatar asked Nov 29 '12 16:11

daedelus_j


People also ask

Which among these is are the correct way of accessing values of nested objects?

Array reduce method is very powerful and it can be used to safely access nested objects.

How to work with nested objects in JavaScript?

Accessing nested json objects is just like accessing nested arrays. Nested objects are the objects that are inside an another object. In the following example 'vehicles' is a object which is inside a main object called 'person'. Using dot notation the nested objects' property(car) is accessed.


2 Answers

Sure, you can define an extra schema, but mongoose is already doing this for you.

It is stored at

PersonSchema.path('arrayAttr').schema

So you can set a virtual by adding it to this schema

PersonSchema.path('arrayAttr').schema.virtual('full').get(function() {
  return this.attr1 + '.' + this.attr2
})
like image 124
Jannik S. Avatar answered Sep 19 '22 05:09

Jannik S.


If you want a calculated value from all the array elements here's an example:

const schema = new Schema({
    name:         String,
    points: [{
        p:      { type: Number, required: true },
        reason: { type: String, required: true },
        date:   { type: Date,   default: Date.now }
    }]
});

schema.virtual('totalPoints').get(function () {
    let total = 0;
    this.points.forEach(function(e) {
        total += e.p;
    });
    return total;
});

User.create({
    name:   'a',
    points: [{ p: 1, reason: 'good person' }]
})

User.findOne().then(function(u) {
    console.log(u.toJSON({virtuals: true}));
});

Returns to:

{ _id: 596b727fd4249421ba4de474,
  __v: 0,
  points:
   [ { p: 1,
       reason: 'good person',
       _id: 596b727fd4249421ba4de475,
       date: 2017-07-16T14:04:47.634Z,
       id: '596b727fd4249421ba4de475' } ],
  totalPoints: 1,
  id: '596b727fd4249421ba4de474' }
like image 40
Gianfranco P. Avatar answered Sep 22 '22 05:09

Gianfranco P.