Mr T
Mr T

Reputation: 1000

if/else statement in a for loop

I am writing individual results from a JSON array to a Parse.com database. The attempted process is as follows:

For each result item in JSON array - search column "EAN" in class "TestClass" for content of "JSON Result:EAN".

Then...

If JSON Result:EAN is present: - console.log("Already In DB");

Else

Write JSON Result:EAN to Parse DB:EAN & JSON Result:name to Parse DB:name

The problem that I am experiencing is that if I have say 20 results with different names & EAN numbers - assuming that none are in the database, the below script writes 20 results to the database, but each write contains the name & EAN number of the last JSON result.

Here is a simplified version of my production code:

$.ajax(settings).done(function(response) {
    var Products = Parse.Object.extend("TestClass");

    for (i in response.Products) {
        var name = response.Products[i].Name;
        var EAN = response.Products[i].EANBarcode;

        var query = new Parse.Query(Products);
        query.equalTo("EAN", EAN);
        query.find({
            success: function(results) {
                if (results.length > 0) {
                    var no = results[0].get("EAN");
                    var title = results[0].get("name");
                    console.log("ALEADY HERE: " + "[" + no + "] " + title);
                } else {
                    console.log('No matching records for' + name);
                    var newProduct = new Products();
                    newProduct.set("name", name);
                    newProduct.set("EAN", EAN);
                    newProduct.save({
                        success: function() {
                            console.log("Saved: " + name);
                        },
                        error: function(error) {
                            console.log("Error: " + error.message);
                        }
                    });
                }
            },
        });
    });

If I do not query the product & write it straight to the database (i.e: don't use query.find) & apply the code as follows, the database entries replicate the 20 different results as you would expect:

$.ajax(settings).done(function(response) {

    var Products = Parse.Object.extend("TestClass");

    for (i in response.Products) {

        var name = response.Products[i].Name;
        var EAN = response.Products[i].EANBarcode;

        var newProduct = new Products();

        newProduct.set("name", name);
        newProduct.set("EAN", EAN);

        newProduct.save({
            success: function() {
                console.log("Saved: " + name);
            },
            error: function(error) {
                console.log("Error: " + error.message);
            }
        }),
    });
});

I cannot figure out why the lower code works, but it then does not when you enter the .find command?

Upvotes: 2

Views: 104

Answers (1)

danh
danh

Reputation: 62676

The way I get my arms around problems like these (multiple asynch operations within loops and conditionals), is to decompose to simpler operations and connect them with promises. So, for example, lets have a function that finds a Product given an "EAN"...

function productWithEAN(EAN) {
    var Products = Parse.Object.extend("TestClass");
    var query = new Parse.Query(Products);
    query.equalTo("EAN", EAN);
    return query.first();
}

And here's one that creates a Product with a name and an EAN...

function createProduct(name, EAN) {
    var Products = Parse.Object.extend("TestClass");
    var newProduct = new Products();
    newProduct.set("name", name);
    newProduct.set("EAN", EAN);
    return newProduct.save();
}

Now, lets loop response.Products, look for matching Products in parse, creating if we don't find a match...

function findOrCreateProducts(response) {
    var promises = response.Products.map(function(p) {
        var name = p.Name;
        var EAN = p.EANBarcode;
        return productWithEAN(EAN).then(function(product) {
            return (product)? product : createProduct(name, EAN);
        });
    });
    return Parse.Promise.when(promises).then(function() {
        // return a proper array
        return Array.prototype.slice.call(arguments);
    });
}

EDIT Clarifying the data model a little, The following assumes a class called UserInventory, which has at a minimum two pointer attributes: one pointer to Product called "product", and one pointer to Parse.User called "user".

// return a promise to create user inventory for a user and product
function createUserInventory(user, product) {
    var UserInventory = Parse.Object.extend("UserInventory");
    var newUI = new UserInventory();
    newUI.set("user", user);
    newUI.set("product", product);
    return newUI.save();
}

// return a promise to create user inventory for a user and product, only if one doesn't exist
function findOrCreateUserInventory(user, product) {
    var query = new Parse.Query("UserInventory");
    query.equalTo("user", user);
    query.equalTo("product", product);
    return query.first().then(function(userInventory) {
        return (userInventory)? userInventory : createUserInventory(user, product);
    });
}

// return a promise to create a user's inventory from a remote api response
function buildUserInventoryFromRemoteSearch(user, response) {
    return findOrCreateProducts(response).then(function(products) {
        var promises = products.map(function(product) {
            return findOrCreateUserInventory(user, product);
        });
        return Parse.Promise.when(promises).then(function() {
            // return a proper array
            return Array.prototype.slice.call(arguments);
        });
    });
}

Call it...

$.ajax(settings).done(function(response) {
    var user = Parse.User.current();
    buildUserInventoryFromRemoteSearch(user, response).then(function(result) {
        // at this point, everything is done
    }, function(error) {
        // something went wrong
    });
});

Incidentally, at some time, it will be necessary to fetch a user's inventory...

function userInventoryForUser(user) {
    var query = new Parse.Query("UserInventory");
    query.equalTo("user", user);
    query.include("user");
    query.include("product");
    return query.find();
}

Hopefully you can study this to get the hang of the approach. Key idea: is small, promise-returning functions that do logical chunks or work.

Upvotes: 2

Related Questions