imalik8088
imalik8088

Reputation: 1631

update mongoose document before returning

I want to add a property to the returned docs of mongoose query. This property is as well a mongoose query

Buildung.find({_id: {$in: user.favorites}}, function (err, buildungs) {
      if (err) { return res.status(400).json({error: err}); }

      const mbuildungs = buildungs.map(buildung => {

        let buildungObject = buildung.toObject();

        const now = new Date();
        Time.findOne({buildung: buildung._id, validFrom: { $lte: Date.parse(now) }}, null,
          {sort: {validFrom: -1}}, (err, time)=> {

            buildungObject.time = time;
          });

        return buildungObject;

      });

      return res.status(200).json({buildungs: mbuildungs})
});

The modified object should be returned, but it isnt adding the property time to the result.

I've also attempted to work with callback function but I could solve the problem, that I want to achieve.

Update

1) Schema
// Time
const TimeSchema = new mongoose.Schema({
validFrom: {type: Date, required: true},
....
building: {type: Schema.Types.ObjectId, ref: 'Building', index: true, required: true}

// Building
const BuildingSchema = new mongoose.Schema({
  name: {type: String, required: true},
  .....
  // no relation to timeSchma
})

Upvotes: 2

Views: 1489

Answers (1)

GPX
GPX

Reputation: 3645

There are a few things that you could fix in your code!

  1. Asynchronous functions cannot be called inside a map. You'd need some way to aggregate every findOne result - the easiest way out is using the async module. However, I'd personally recommend a Promise-based solution as that looks much cleaner.

  2. Mongoose returns its own Object (called MongooseDocument) that is decorated with a lot of Mongoose-specific functions, and that makes the return object act differently. To work around this, use lean(). This returns a plain object that you can freely modify as you would any other JS object. Using lean() also has the additional advantage of huge performance improvements!

I've included both these changes to your code —

const async = require('async');

function findBuildungTime(buildung, done) {
    const now = new Date();
    Time.findOne({ buildung: buildung._id, validFrom: { $lte: Date.parse(now) } }, null, { sort: { validFrom: -1 } })
        .lean()
        .exec((err, time) => {
            buildung.time = time;
            return done(err, buildung);
        });
}

Buildung.find({ _id: { $in: user.favorites } })
    .lean()
    .exec((err, buildungs) => {
        if (err) {
            return res.status(400).json({ error: err });
        }
        async.map(buildungs, findBuildungTime, (err, results) => {
            return res.status(200).json({ buildungs: results })
        });
    });

Upvotes: 4

Related Questions