Search code examples
mongoosemongoose-schema

Mongoose save() returns before findOne()


I am implementing an approval system using Mongoose, Express and NodeJS.

Each post has 2 set of approvals.

I have implemented model as below:

Post Schema:
var PostSchema = new Schema({
UserId: { type: ObjectId, unique: true, default: null },
/..
.. Object related fields
../
    Approval1: Object, //chidschema objects of approver
    Approval2: Object
});

Approval Mapping Schema:
var ApprovalMapSchema = new Schema({
  UserId: { type: ObjectId, unique: true, default: null },
  Approver1Id: { type: ObjectId, default: null },
  Approver2Id: { type: ObjectId, default: null }
});

I am trying to find the mapping first in my function and then update the main post object on save.

I need to retrieve both approver IDs before saving new Post.

Please suggest a good way to go about it. I am currently doing:

  1. Save new Post object with Save //returns after 2nd step, i knw save in Mongoose in async but i do not want step 2 be called before this
  2. Get approver IDs with findOne on ApprovalMapSchema
  3. Update Post object with approver entries.

    post.save(function(err, doc) { if (err) {} else { console.log({success: true, msg: 'Successful created new post', content: doc}); } });

    /*var actId = activation._id, distributorId, ttlId;
    
    var approvalMap = ApprovalMap.findOne({ userId: myUserId }, function(err, appMap) {
        if (err) throw err;
        else{           
            Approver1Id = appMap.Approver1Id;
            Approver2Id = appMap.Approver2Id;
        }
    });
    
    // Create child objects after this and update as subdocument
    

This is not working for me. Please Help!


Solution

  • I am having a difficult time understanding your question. But it sounds like you want to do something like this (you will need to modify this based on what you want to do, but hopefully it shows you one way of handling the async behavior):

        //This will run a query that returns a document where userId == myUserId
    
        ApprovalMap.findOne({ userId: myUserId }, function(err, appMap) {
    
            if (err) throw err;
    
            //Once the query is complete function(err, appMap) will be called
            //err will contain an error object if there was an error
            //appMap will be the data returned by the query.
            //within this block you can run another query
            //for example
    
            ApprovalMap.findOne({approved:'some variable'},function(err, secondQueryData){
    
                if (err) throw err;
    
                //after this query is complete function(err, secondQueryData) will be called
                //once again the err argument will be an error, and the 
    
                //secondQueryData argument will contain your return data
        
                //here you can do something with the data
                //for example, log the results
    
                console.log(secondQueryData)
            })
        });
    

    As you can see, you can nest additional queries or steps within the callbacks of other queries. This will ensure things are run in the correct order. you may also want to checkout the npm async library, or a promise library like q or bluebird. They also have some great solutions for handling the async behavior in node.