问题
I am using Sails v0.11 and am developing an standalone importer script in order to import data to mongoDB and - that is now the not-working part - build the associations between the models.
For this process I introduced temporary helper properties in the models in order to find the associated records and replace them by in real MongoDB _ids.
The script starts Sails in order to be able use its features (waterline, etc.):
var app = Sails(); app.load({ hooks: { grunt: false }, log: { level: 'warn' } }, function sailsReady(err){
processUsers() finds all users and their _ids and iterates over them to invoke a second function addOrgsToOneUser()
var processUsers = function() { // Iterate through all users in order to retrieve their _ids and app.models['user'].native(function(err, collection) { collection.find({}, projectionOrgInUser).toArray(function (err, users) { Async.eachSeries(users, function (user, next){ // prepare userInOrgs whereUserInOrg = { orgId: { $in: userInOrgs } }; //This is invoking addOrgsToOneUser(user, whereUserInOrg); next(); }, function afterwards (err) { if (err) { console.error('Import failed, error details:\n',err); return process.exit(1); } console.log("done"); return process.exit(0); // This returns too early, not executing the addOrgsToOneUser }); }); }); };
addOrgsToOneUser() finds all orgs belonging to THIS user and updates then the orgs array property of THIS user
var addOrgsToOneUser = function(user, whereUserInOrg) { var projectionUserInOrg = "..."; // Find all orgs that this user is associated to and store it in inOrgs app.models['org'].native(function(err, collection) { collection.find(whereUserInOrg, projectionUserInOrg).toArray(function (err, orgs) { // prepare inOrgs which is needed for updating //update user to have an updated orgs array based on inOrgs. app.models['user'].update({'id' : user._id.toString()}, {'orgs': inOrgs}).exec(function afterwards(err, updated){ console.log('Updated user ' + user._id.toString() + ' to be in their orgs'); }); }); }); }
Problem:
- Process.exit(0) is called before the query/update of saddOrgsToOneUser() has completed. It behaves as expected if saddOrgsToOneUser() contains just a console.log for instance, but queries are triggered ansynchronously of course.
- In case I comment out Process.exit(0), the script never stops, but the queries are executed as intented.
- As the script will have further nested queries, I need a better approach to this as manually kill this script ...
- How is nesting queries and iterating over their results done properly?
Thank you very much, Manuel
回答1:
addOrgsToOneUser is asynchronous. next() needs to be called after everything is done inside addOrgsToOneUser. The way I would do it is to pass in a callback (next) and call it when everything is done. So the call is
addOrgsToOneUser(user, whereUserInOrg, next);
and the addOrgsToOneUser will have an extra argument:
var addOrgsToOneUser = function(user, whereUserInOrg, callback) {
var projectionUserInOrg = "...";
// Find all orgs that this user is associated to and store it in inOrgs
app.models['org'].native(function(err, collection) {
collection.find(whereUserInOrg, projectionUserInOrg).toArray(function (err, orgs) {
// prepare inOrgs which is needed for updating
//update user to have an updated orgs array based on inOrgs.
app.models['user'].update({'id' : user._id.toString()}, {'orgs': inOrgs}).exec(function afterwards(err, updated){
console.log('Updated user ' + user._id.toString() + ' to be in their orgs');
callback(); // your original next() is called here
});
});
});
}
来源:https://stackoverflow.com/questions/32058797/sails-js-nested-mongodb-queries