Antonio Antonio - 1 month ago 12
Node.js Question

Node.js API return different values for the same request

I'm learning to use Node.js + Express to build a REST API. In this API
I have the following method:

apiRouter.route('/training/session/byId/:id_session')
// ===== GET =======
.get(function(req, res) {

//Get the session
Session.findById(req.params.id_session, function(err, session) {

//Get an array of exercise associated with the session
Exercise.find({session: session._id}, function(err, exercise) {
let movements = [];
let sets = [];
let i = exercise.length-1;

//For every exercise get the movements and the sets
exercise.forEach(function (ex,index) {
Movement.findById(ex.movement,function(err,movement){
if(movement)
movements.push(movement);

//***** Here?
Set.find({exercise: ex}, function (err, set) {
if(set.length)
sets.push(set);
if(index == i){
res.json({ message: 'ok' ,session,exercise,movements,sets});
}
})
})
})
});
});
})


The idea is obtain all the session related information from the database.

First:
I think that is not the correct way of make multiple querys and return an object with the info of all the querys, but I'm novice with the async working of Node... So what is the correct way to make multiple querys where the data of one query depends of other query?

Second: In the Front-End (React + Redux) I'm making Ajax request with axios and for the same Ajax request sometimes not all 'sets' are fetched (//***** Here?). The problem is in the API?

Thanks in advance.

EDIT: DB models

Session:

var SessionSchema = new Schema({
date: {type: Date, default: Date.now },
time: Number, //Time in seconds
user: {required: true, type: mongoose.Schema.Types.ObjectId, ref: 'User'},

});


Exercise:

var ExerciseSchema = new Schema({
session: {type: mongoose.Schema.Types.ObjectId, ref: 'Session'},
movement: {type: mongoose.Schema.Types.ObjectId, ref: 'Movement'},
timestamp: {
type: Date,
default: Date.now
}
});


Set:

var SetSchema = new Schema({
repetitions: Number,
weight: Number,
rest: Number,
timestamp: {
type: Date,
default: Date.now
},
exercise : {type: mongoose.Schema.Types.ObjectId, ref: 'Exercise'}

});


Movement:

var MovementSchema = new Schema({
name: { type: String, required: true, index: true, unique: true },
material:{ type: String, required: true},
muscles : [{
name : { type: String, required: true},
percentage : { type: Number, required: true}
}]
});

Answer
Set.find({exercise: ex}, function (err, set) {  
if(set.length)
    sets.push(set);      
}).then(function(set){
    if(index == i){
        res.json({ message: 'ok' ,session,exercise,movements,sets});
    }
})

Of course my prev answer wouldn't work. The set query callback would execute after the if(index == i). Actually I'm not sure this will produce different results from your code. I've never actually used Mongoose but as far as I know, you can't do joins so nested queries is the way to do it.

You might want to consider using promises. Not necessary, but they make your code easier to read and think about: http://eddywashere.com/blog/switching-out-callbacks-with-promises-in-mongoose/

It might make more sense as well to create a single result object that you build up as the queries return so you end up sending a single JSON object representing your session that looks like:

{
    exercises: [
                    {
                        sets: [],
                        movements: [],
                    },
                    {
                        sets: [],
                        movements: [],
                    },
                    ...
                ]
}