问题
I've done a parse job that checks every "X" time if "emailSent" is false, for each user. If it is, I call a function to send a email and change the "emailSent" to true. That works. My problem is with the function "getMaxId". I need to return the maxid value to change each user "id_client" column, but I don't know how. I've tried this but it doesn't work. This is writing nothing: "console.log("Write somethingggg"); "
Here is the code...
Parse.Cloud.job("test", function(request, status) {
// Set up to modify user data
Parse.Cloud.useMasterKey();
var texto = "New verified emails:\n\t";
// Query for all users
var query = new Parse.Query(Parse.User);
//query.equalTo("emailVerified", true);
query.equalTo("emailSent", false);
query.each(function(user) {
user.set("emailSent", true);
user.save();
var datos = user.get("email")+"\n";
texto=texto+datos;
Parse.Cloud.run("getMaxId", {},{
success: function(results) {
console.log("Write somethingggg");
user.set("id_client", "gofoadasda");
user.save();
var datos = user.get("id_client")+"\n";
//console.log("id_client: "+datos);
response.success();
},
error: function(results, error) {
response.error(errorMessageMaker("running chained function",error));
}
}).then(function() {
// Set the job's success status
}, function(error) {
// Set the job's error status
status.error("Uh oh, something went wrong.");
});
Parse.Cloud.run("sendEmail",{
success: function(results) {
response.success(results);
},
error: function(results, error) {
response.error(errorMessageMaker("running chained function",error));
}
});
}).then(function() {
// Set the job's success status
console.log("texto: "+texto);
status.success("Migration completed successfully.");
}, function(error) {
// Set the job's error status
status.error("Uh oh, something went wrong.");
});
});
Parse.Cloud.define("sendEmail", function(request, response) {
Parse.Cloud.httpRequest({
url: 'http://www.example.com/sendemail.php',
params: {
email : 'email@email.com'
},
success: function(httpResponse) {
console.log(httpResponse.text);
},
error: function(httpResponse) {
console.error('Request failed with response code ' + httpResponse.status);
}
});
});
Parse.Cloud.define("getMaxId", function(request,response) {
var query = new Parse.Query(Parse.User);
query.descending("id_client");
query.find({
success: function(results) {
var idmax=results[0].get("id_client")
console.log("idmax: "+idmax);
response.success(idmax);
},
error: function() {
response.error(" is an error");
}
});
});
FIRST CHANGES:
After @danh help, I tried to do what I need, changing some code:
Important: id_client is a int value which it's unique for each user, it starts at 20000.
- get all the users with the flag sentEmail=false.
- For each of those users, getMaxId (this returns the actual max "id_client" value for all the users).
- Change value of sentEmail to true, set user id_client to the actual max id.
- Send email.
New code (sendEmail has no changes):
var _ = require('underscore');
// return a promise to get the max value of id_client in the user table
function getMaxId(user) {
var query = new Parse.Query(Parse.User);
//return query.count();
query.descending("id_client");
query.limit(1);
return query.find().then(function(users) {
if(users[0].get("id_client")<20000){ //No users yet.
user.set("id_client", 20000); //First id:20000
user.save();
return 20000;
}
else{ //There are users. Get the maxId and increment +1.
user.set("id_client", users[0].get("id_client")+1);
user.save();
return (users.length)? users[0].get("id_client")+1 : 0;
}
});
}
// return a promise for users with emailSent flag == false
function usersWithUnsentEmail() {
var query = new Parse.Query(Parse.User);
query.equalTo("emailSent", false);
return query.find();
}
// return a promise to send email to the given user, and to set its
// emailSent flag = true
function sendEmailToUser(user) {
return sendEmail(user.get("email")).then(function() {
user.set("emailSent", true);
return user.save();
});
}
Parse.Cloud.job("test", function(request, response) {
// Set up to modify user data
Parse.Cloud.useMasterKey();
usersWithUnsentEmail().then(function (users){
var emailPromises = _.map(users, function(user) {
//what I understand is that here, for each user, we call getMaxId, getting the actual max id_client, and then, we pass it to "sendEmailToUser".
return getMaxId(user).then(function(max){
return sendEmailToUser(user);
});
});
return Parse.Promise.when(emailPromises);//This means that we have looped all users, is it?
}).then(function(results) {
response.success(results);
}, function(error) {
response.error(error);
});
});
I've tested this with 2 users with the flag "sentEmail" = false and actual max id_client was 20001 Result:
- sentEmail flags changed correctly.
- 2 emails sent correctly.
- Error here: id_client for both users changed to 20002. It has to be 20002 and 20003.
Logs in parse:
I2015-04-22T09:44:13.433Z] v90: Ran job test with:
Input: {}
Result: undefined
E2015-04-22T09:44:29.005Z] v90: Ran job test with:
Input: {}
Failed with: Error: Job status message must be a string
at updateJobMessageAndReturn (<anonymous>:790:7)
at Object.success (<anonymous>:828:9)
at main.js:217:18
at e (Parse.js:3:8736)
at Parse.js:3:8185
at Array.forEach (native)
at Object.x.each.x.forEach [as _arrayEach] (Parse.js:1:661)
at c.extend.resolve (Parse.js:3:8136)
at Parse.js:3:8815
at e (Parse.js:3:8736)
EDITED:
We need their email and the id_client that we will assign them.
May be I haven't explained well, the email won't be sent to the user email, the email will be sent to a email that I've determined in the sendemail.php script, and it will be always the same.
I'll explain: You have a local database at home, and parse database. When this Parse.job is called, it will send an email to you (email of php) with a list of the email and the id_client of each user updated. Now you can manually update your local database with the email received info.
So, for this reason, it will be better to send only one email, at the end of all the updates. (I didn't say that because I had a lot of problems yet trying to understand how cloudCode works...)
回答1:
There are a few things that need fixing in the code: (1) as a rule, use promises if you're doing more than two consecutive asynchronous things, (2) don't call Parse.Cloud.run from cloud code, it's what you call from clients who wish to invoke cloud functions, (3) style-wise, you'll go nuts trying to figure it out later on unless you break the code into small, promise-returning steps.
I've applied all three bits of advice to your code. I don't fully understand the logic as described in code and text, but hopefully I got close enough for you to make sense of it.
// using underscore js, which provides _.map below as well as loads of other useful stuff
var _ = require('underscore');
// return a promise to get the max value of id_client in the user table
function getMaxId() {
var query = new Parse.Query(Parse.User);
query.descending("id_client");
query.limit(1);
return query.find().then(function(users) {
return (users.length)? users[0].get("id_client") : 0;
});
}
// return a promise for users with emailSent flag == false
function usersWithUnsentEmail() {
var query = new Parse.Query(Parse.User);
query.equalTo("emailSent", false);
return query.find();
}
// return a promise to send email to the given user, and to set its
// emailSent flag = true, and to set its clientId to the passed value
function sendEmailToUser(user, idClient) {
return sendEmail(user.get("email")).then(function() {
user.set("emailSent", true);
user.set("id_client", idClient);
return user.save();
});
}
// return a promise to send email to the given email address via an http service
function sendEmail(email) {
var params = {url: 'http://www.example.com/sendemail.php', params: {email : email} };
return Parse.Cloud.httpRequest(params);
}
Parse.Cloud.job("test", function(request, response) {
// Set up to modify user data
Parse.Cloud.useMasterKey();
var maxIdClient;
getMaxId().then(function(result) {
maxIdClient = result;
return usersWithUnsentEmail();
}).then(function(users) {
var emailPromises = _.map(users, function(user) {
return sendEmailToUser(user, maxIdClient);
});
return Parse.Promise.when(emailPromises);
}).then(function(results) {
response.success(results);
}, function(error) {
response.error(error);
});
});
EDIT - we're kind of working on logic here particular to the app, as opposed to the concept of promises, but here goes anyway. To restate the functional requirement: We want a job to find users who have not yet been recorded in another database, represented by a flag called "emailSent". Our goal is to assign these users a unique id, and send their info (for now, we'll say email address and that id) via email to some fixed destination.
So
// getMaxId() from above is almost ready, except the minimum id_client
// value is 20000, so change the line that set this to:
return (users.length)? users[0].get("id_client") : 20000;
// usersWithUnsentEmail() from above is fine
// delete sendEmailToUser() since we're not doing that
// change sendEmail() to take an array of users to be conveyed to
// the other database. Send email about them, then change each user's
// emailSent status and save them
function sendEmail(users) {
var params = {url: 'http://www.example.com/sendemail.php', params: {users : JSON.stringify(users)} };
return Parse.Cloud.httpRequest(params).then(function() {
_.each(users, function(user) {user.set("emailSent", true);});
return Parse.Object.saveAll(users);
});
}
// add a function that takes an array of users, updates their
// id_client to be a new, unique value, and sends mail about them
// to a remote server
function synchUsers(users, idMax) {
_.each(users, function(user) {
user.set("id_client", idMax);
idMax += 1;
});
return sendEmail(users);
}
// update the job taking all this into account
Parse.Cloud.job("test", function(request, response) {
// Set up to modify user data
Parse.Cloud.useMasterKey();
var maxIdClient;
getMaxId().then(function(result) {
maxIdClient = result;
return usersWithUnsentEmail();
}).then(function(users) {
return synchUsers(users, maxIdClient+1);
}).then(function(results) {
response.success(results);
}, function(error) {
response.error(error);
});
});
来源:https://stackoverflow.com/questions/29771593/how-to-chain-functions-in-parse-cloudcode