, . -, 10000 4 . , socketTimeoutMS connectTimeoutMS mongoose , , - . , @neil lunn for. , , ,
let BATCH_SIZE = 500
Array.prototype.chunk = function (groupsize) {
    var sets = [];
    var chunks = this.length / groupsize;
    for (var i = 0, j = 0; i < chunks; i++ , j += groupsize) {
        sets[i] = this.slice(j, j + groupsize);
    }
    return sets;
}
function upsertDiscountedProducts(products) {
    
    let chunks = products.chunk(BATCH_SIZE), current = 0
    console.log('Number of chunks ', chunks.length)
    let bulk = models.Product.collection.initializeUnorderedBulkOp();
    
    let timestamp = new Date(),
        
        pendingCount = 0,
        inserted = 0,
        upserted = 0,
        matched = 0,
        modified = 0,
        removed = 0,
        
        upsertHappened = false;
    
    load()
    function load() {
        
        if (current < chunks.length) {
            console.log('Current value ', current)
            for (let i = 0; i < chunks[current].length; i++) {
                
                let item = chunks[current][i]
                
                item.updatedAt = timestamp;
                bulk.find({ _id: item._id })
                    .upsert()
                    .updateOne({
                        "$set": item,
                        
                        "$setOnInsert": {
                            "createdAt": timestamp
                        }
                    })
            }
            
            bulk.execute((error, result) => {
                if (error) {
                    console.error('Error while inserting products' + JSON.stringify(error))
                    next()
                }
                else {
                    
                    upsertHappened = true;
                    inserted += result.nInserted
                    upserted += result.nUpserted
                    matched += result.nMatched
                    modified += result.nModified
                    removed += result.nRemoved
                    
                    next()
                }
            })
        }
        else {
            console.log("Calling finish")
            finish()
        }
    }
    function next() {
        current++;
        
        bulk = models.Product.collection.initializeUnorderedBulkOp();
        setTimeout(load, 0)
    }
    function finish() {
        console.log('Inserted ', inserted + ' Upserted ', upserted, ' Matched ', matched, ' Modified ', modified, ' Removed ', removed)
        
        if (upsertHappened) {
            console.log("Calling remove")
            remove()
        }
    }
    
    function remove() {
        models.Product.remove(
            {
                "$or":
                [{
                    "updatedAt": { "$lt": timestamp }
                },
                {
                    "discount": { "$eq": 0 }
                }]
            }, (error, obj) => {
                if (error) {
                    console.log('Error while removing', JSON.stringify(error))
                }
                else {
                    if (obj.result.n === 0) {
                        console.log('Nothing was removed')
                    } else {
                        console.log('Removed ' + obj.result.n + ' documents')
                    }
                }
            }
        )
    }
}