Mongoose - REST API - schema querying another model

I am trying to avoid DB callback requests.

Assuming you have two schematics that look like this:

1st) User schema

 username : {type: String, unique: true},
 age : {type: Number}

      

2nd) Action plan

 owner: [{type: Schema.Types.ObjectId, ref: 'User'}],
 city: {type: String},
 date: {type: Date}

      

So far so good.

Now let's say you have a route to /user/:id

, what you expect is get username

and age

, but what if I would also like to return the last activity on that route

EDIT: Please note that is latest activity

not a value in the database. it is automatically calculated asactivity.find({owner: ObjectId(id)}).sort({date: -1}).limit(1)

What is being done right now:

User.findOne({username:req.params.username}).lean().exec(function(err,userDoc)
{

   if(err) return errHandler(err);

   Activity.findOne({owner:userDoc.username}).sort({date:-1}).exec(function(err,EventDoc){

     if(err) return errHandler(err);

     userDoc.latest_activity = EventDoc._id;

     res.json(userDoc);
     res.end();

   })

})

      

The problem with the above snippet is that it is difficult to maintain.What if we want to add more to this API functionality? We would end up with the hellish requests callback if we didn't execute Q.

We tried to look at Virtual, but the problem is that you cannot actually query inside mongoose Virtual as it returns a race state and you most likely won't get this document in time.

We also tried to look at the infill, but we were unable to do that as the filing documentation is very poor.

Question: Is there a way to make this more modular?

Is there a way to avoid the addon request callback?

For example, is it possible?

    User.findOne({username:req.params.username}).lean().populate(
{path:'Event',sort:{Date:-1}, limit(1)}
).exec(function(req,res))...

      

Thank!

+3


source to share


2 answers


Inspired by @ BrianShambien's answer, you can go with saving the post, but instead of just keeping it _id

from the user, you only keep the last activity subdock. Then when you grab that user, it has the last action right there.

User model

username :     {type: String, unique: true},
age :          {type: Number},
last_activity: ActivitySchema

      

Then you create a fallback to save messages to ActivitySchema



ActivitySchema.post('save', function(doc) {
    UserSchema.findOne({username: doc.owner}).exec(function(err, user){
        if (err) errHandler(err);

        user.last_activity = doc;

        user.save(function(err) {
            if (err) errHandler(err);
        });
    });
});

      

********** UPDATE ************

This should include an update for the user if it is not the owner but is part of this action.

ActivitySchema.post('save', function(doc) {
    findAndUpdateUser(doc.owner, doc);

    if (doc.participants) {
        for (var i in doc.participants) {
            findAndUpdateUser(doc.participants[i], doc);
        }
    }
});

var findAndUpdateUser = function (username, doc) {
    UserSchema.findOne({username: username}).exec(function (err, user) {
        if (err) errHandler(err);

        user.last_activity = doc;

        user.save(function (err) {
            if (err) errHandler(err);
        });
    });
});

      

+4


source


In this case, the best way to deal with this would be to add a save link to your schema Activity

to store the latter _id

in latest_activity

your schema path User

. This way, you will always have access to the id without having to make an additional request.



ActivitySchema.post('save', function(doc) {
    UserSchema.findOne({username: doc.owner}).exec(function(err, user){
        if (err)
            console.log(err); //do something with the error
        else if (user) {
            user.latest_activity = doc._id;

            user.save(function(err) {
                if (err)
                    console.log(err); //do something with the error
            });
        }
    });
});

      

+4


source







All Articles