2

I've created a loop to add products (with data) to different regions. To start with I want to add all products to all regions. I will then (in a different operation) remove products from these regions.

The premise of the site is that objects will be able to be reserved by a user in a region, that will make that object unavailable in that region but still available in other regions. I save the users region on sign up and only allow them to see the objects available in their region.

I have created objects called Regions and I'm adding each product to an array within regions. The reason I am storing them within regions is in the future I am expecting hundreds of different products and believe that just returning all the items within a region array will be much easier on the server than checking a value within each product individually.

My problem is that

when running my code, I am getting duplicates of each object within my page.

The code I am using is:

dummyregions.forEach(function(seed){
    Region.create(seed, function(err, region){
        if(err){
            console.log(err);
        } else {
            dummyproducts.forEach(function(seedprod){
                Product.create(seedprod, function(err, product){
                    if(err){
                        console.log(err);
                    } else {
                        region.products.push(product);
                        region.save();
                    }
                });
            });
        }
    })
});

dummyRegions is an object, containing a name "string" and an array = []

dummyproducts contains a name "string", category "string" and a thumbnail image url "string"

I only have 4 test items in dummy products and 3 regions, however this is the result I'm getting: Duplicate Items on each Region

Any help would be much appreciated!

2
  • Are you sure those are not in the database already? Commented Oct 3, 2017 at 21:27
  • I clear both collections (region and products) from the database before running the script above. I've double checked to make sure they are not present before the script. The duplicates are created with the code above. Commented Oct 4, 2017 at 12:42

1 Answer 1

1

Because Array.forEach is blocking for asynchronous methods, you are getting duplicates. For an asynchronous-friendly version of Array.forEach, you can the async module or Promises.

The latter can be followed with this example (untested):

let regionsPromise = Region.insertMany(dummyregions);
let productsPromise = Product.insertMany(dummyproducts);

Promise.all([regionsPromise, productsPromise])
    .then(([regions, products]) => {

        console.log(regions); // check regions array
        console.log(products); // check products array

        let ids = regions.map(r => r._id);
        console.log(ids); // check ids

        Region.update(
            { '_id': {  '$in': ids } },
            { '$push': { 'products': { '$each': products } } },
            { 'multi': true }
        );
    })
    .catch((err) => {
        /* Error handling */
        console.error(`Error ${err.message}`);
    });

and for a version which uses ES7's async/await:

(async () => {

    try {

        const regions = await Promise.all(dummyregions.map(async (reg) => {
            await Region.create(reg);
        }));

        const products = await Promise.all(dummyproducts.map(async (prod) => {
            await Product.create(prod);
        }));

        for (let region of regions) {
            await region.findByIdAndUpdate(region._id, { 
                '$push': { 
                    'products': { '$each': products } 
                } 
            });
        }

        /*

        if (regions && regions.length) {
            await Promise.all(
                regions.map(async (r) => {
                    await r.findByIdAndUpdate(r._id, { 
                        '$push': { 
                            'products': { '$each': products } 
                        } 
                    });
                })
            );
        }

        */

    } catch (err) {
        console.error(`Error ${err.message}`);
    }
})();
Sign up to request clarification or add additional context in comments.

5 Comments

Thanks so much for your reply. I'm not actually that familiar with ES16 and ES17, So I definitely need to read up on this> I've tried implementing the first solution you suggested, using promises, and I'm not encountering any errors, but the regions don't have any objects inside them. Obviously, i'm not asking you to write my code for me (although I really do appreciate your help), but do you have any pointers on where I can research why there are no products inside my regions? Thanks again!
You could log to console the results from the fulfilled promises, that's the first step I could take, as in the above edit. Also, check if your Regions model has the products array field explicitly declared in the schema definition.
The regions and products are being created correctly, the id's are logging correctly and each region does contain an empty array of products [] when logged. It seems like the Update function on the Region model isn't working correctly, i've tried changing it to the following: Region.findByIdAndUpdate( { '_id': { '$in': ids } }, { '$push': { 'products': { '$each': products } } } ) }) However, still no luck
findByIdAndUpdate() takes in a string as the first argument which is a single document id, not an object so that wont work when you want to update multiple documents. Try setting the { 'multi': true } option in the update method as Region.update( { '_id': { '$in': ids } }, { '$push': { 'products': { '$each': products } } }, { 'multi': true } );
That's worked, thank you so much for all of your help!

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.