I have a scenario in which I'm trying to determine how many new "payers" a company has for the current month. The code I have works, I can log the results and get the number of expected new payers for the company. However, the method is returning 0 because the final code is executed before the Promise has finished.
I think the problem is that the promises are not chained, but nested, I tried chaining them but it just gave errors. Is there anything obviously wrong with the code below?
Parse.Cloud.define('cloudMethod', function(request, response) {
if (!request.user) {
response.error('Invalid User')
return
}
// Set up now date
const now = new Date()
const thisMonthYear = now.getMonth().toString() + now.getFullYear().toString()
// Setup empty array to hold new monthly payer matches
const newMonthlyDonors = []
// Setup User query
const User = Parse.Object.extend('User')
const userQuery = new Parse.Query(User)
// Step 1: Get company pointer from user
userQuery
.equalTo('username', request.user.get('username'))
.first()
.then(function(user) {
// Step 2: Count payers for that company
var Payment = Parse.Object.extend('Payment')
var paymentQuery = new Parse.Query(Payment)
paymentQuery.equalTo('company', user.get('company'))
// Create a trivial resolved promise as a base case.
var promise = Parse.Promise.as()
paymentQuery.distinct('user').then(function(results) {
// Step 3: Loop through each distinct payer
_.each(results, function(result) {
// For each item, extend the promise with a function.
promise = promise.then(function() {
// Setup new Payment query
const firstPaymentQuery = new Parse.Query(Payment)
/*
Step 4:
Query Payment class by this user,
set payment dates in ascending order
and then take the first one.
*/
firstPaymentQuery
.equalTo('user', result)
.ascending('paymentDate')
.first()
.then(function(firstPayment) {
// Set up user date
const firstPaymentDate = new Date(firstPayment.get('paymentDate'))
const firstPaymentMonthYear = firstPaymentDate.getMonth().toString() + firstPaymentDate.getFullYear().toString()
/*
Step 5:
See if the user's first payment date is equal to the current month
*/
if (firstPaymentMonthYear === thisMonthYear) {
return newMonthlyDonors.push(result)
}
else {
return
}
}, function(error) {
response.error('Query to get users first payment date failed')
})
})
})
return promise
}).then(function() {
/*
FIXME:
This is getting called before the queries above can run.
Which is why it's returning 0...
*/
// Return the matches for this month
response.success(newMonthlyDonors.length)
}, function(error) {
response.error('total user count for company failed')
})
},
function(error) {
console.log('Error retrieving User')
console.log(error)
})
})
The problem was I wasn’t returning the query as the result of the first promise called in the _.each()
so the returned result within that query was never returned.
Referencing the big block of code in the question:
This:
/*
Step 4:
Query Payment class by this user,
set payment dates in ascending order
and then take the first one.
*/
firstPaymentQuery…
Needs to be this:
/*
Step 4:
Query Payment class by this user,
set payment dates in ascending order
and then take the first one.
*/
return firstPaymentQuery…