2

I am writing a javascript code using Parse. I have User class and Subscription class. All users' subscription information are stored on Subscription class so it is like one to many relationship.

I would like to retrieve user information and each user's subscription count and store it in an object array.

What I have tried is as follows:

    var user = Parse.User;
    var query = new Parse.Query(user);
    query.find().then(function(objects) {
        return objects;
    }).then(function (objects) {

        for(var i = 0; i < objects.length; i++) {

            var object = objects[i];

            var subscription = Parse.Object.extend('Subscription');
            var queryForSubscription = new Parse.Query(subscription);
            queryForSubscription.equalTo('subscriptionUser', object);
            queryForSubscription.count().then(function(subscriptions) {

                var userEmail = object.get('email');
                var userDOB = object.get('userDOB');
                var userJoinedAt = object.createdAt;
                var userGender = object.get('userGender') ? 'Male' : 'Female';
                var subscriptionCount = subscriptions;

                var sub = [
                    userEmail,
                    userDOB,
                    userGender,
                    userJoinedAt,
                    subscriptionCount
                ];
                userArray.push(sub);
            });
        }
    });

However, userArray only contains last user's information repetively. I reckon it is because wihitn the second query promise (queryForSubscription).count()) runs after the outer for loop finishes.

Let's say I got User A and User B. User A has two subscriptions whereas User B has none. What I expected is something like this:

    [{User A's email, User A's dob, User A's Gender, User A's Joined Date, 2},
    {User B's email, User B's dob, User B's Gender, User B's Joined Date, 0}]

However, the result is

    [{User A's email, User A's dob, User A's Gender, User A's Joined Date, 2},
    {User A's email, User A's dob, User A's Gender, User A's Joined Date, 0}]

I'm stuck at the moment. Have been trying to use Promise and etc but got no idea..Please help!

UPDATE

GOTTA LOVE SO!!! THANK YOU EVERY SINGLE ONE OF YOU GUYS SO MUCH!! One more question here. Actually, I got one more class called Favourite to get a count of each user's number of favourites.

If the number of User A's favourite is 5 and 3 for User B, the expected result will look like this in the end:

    [{User A's email, User A's dob, User A's Gender, User A's Joined Date, 2, 5},
    {User B's email, User B's dob, User B's Gender, User B's Joined Date, 0, 3}]

I am not too sure where I put a new query for Favourite class...Need your advice again!

5
  • It may be a good idea to put what parse code you have into your question. That way people can see what you have and help you complete it. Commented Jan 22, 2015 at 8:01
  • Thanks Jay! it was my first time to ask a question on stackoverflow :) I just edited my post! Commented Jan 22, 2015 at 8:22
  • What's your problem ? Commented Jan 22, 2015 at 8:24
  • You should read about javascript closures., seem needed for object in the last function Commented Jan 22, 2015 at 8:26
  • Please also add, what is the expected output, and what is the actual result. People now can only guess whats wrong without you explaining, how your result differs from what you expect. Also if there are runtime errors or anything what helps finding the issue, feel free to list it in the question. Welcome to SO :) Commented Jan 22, 2015 at 8:31

2 Answers 2

2

You can go with @Hacketo's answer.

Another hacky way to get around this bug is to use .forEach() :

}).then(function (objects) {
    objects.forEach(function(object) {
        var subscription = Parse.Object.extend('Subscription');
        ...
    });
});

A new object variable will be allocated for each iteration of the loop, and you should escape the "shared var" bug.


pointing out the bug

One of the common javascript pitfalls is : a local variable's scope is not its closest bloc, it is its closest function.

The following snippet :

function (objects) {
    for(var i = 0; i < objects.length; i++) {
        var object = objects[i];
        ...

is actually equivalent to :

function (objects) {
    var i, object;
    for(i = 0; i < objects.length; i++) {
        object = objects[i];
        ...

So the object variable in the OP's code is actually shared by all the created queryForSubscription variables, and when any of the .then(..) callbacks is executed (after the loop finishes, as the OP correctly pointed out), this object variable holds the value of the last item in the array.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks LeGEC!! The best answer everrrrr! I updated my question again. could you please have a look at it again?
2

It seem to be that you need to save the value of object when the last functions are executed. Try this :

for(var i = 0; i < objects.length; i++) {

    var object = objects[i];

    queryForSubscription.count().then(
      (function(myObject){
        return function(subscriptions) {
            var userEmail = myObject.get('email');

            ...    

        };   
      })(object)
    );
}

2 Comments

@LeGEC I don't see where the bug could be, and how this could be solve something. * OP has updated his code ..
my mistake, your fix would do the job

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.