Mongo db update document, with conditional push data

41 Views Asked by At

I use the library Mongoose v "7.3.4" and i have this type of schemas for my collection

const historicalPrice = new mongoose.Schema({
    price: { type: Number, required: true },
    time:  { type: Date, required: true }
})
const sellers = new mongoose.Schema({
    kiabi : { type: [historicalPrice], default: [] },
    OVS:    { type: [historicalPrice], default: [] },
    ZARA:   { type: [historicalPrice], default: [] },
});
const listItem = new mongoose.Schema ({
    t_shirt: sellers,
    shoes: sellers,
    hat: sellers,
})

const profile = new mongoose.Schema({
    id:     { type: String, required: true, unique: true },
    date:   { type: Date, required: true },
    list:   { type: listItem, required: true},
})

//the document type
{
    id: id,
    date: date,
    list: {
        t_shirt: {
            kiabi: [],
            OVS: [],
            ZARA: []
        },
        shoes: {
            kiabi: [],
            OVS: [],
            ZARA: []
        },
        hat: {
            kiabi: [],
            OVS: [],
            ZARA: []
        },
    },
}

I need an asynchronous function written with Mongoose that takes as parameters an identifying ID of the document, an item, and an object containing the prices of the item for some sellers. This function should update the document by adding an object with the new price and the current date to the historicalPrice array, but only if the new price is different from the previous one; otherwise, it should do nothing. Additionally, if the document is not present, it should create the document with these values.

I tried this code and it works, but it has poor performance.

const newData = {
    id: "123456",
    item: "t_shirt",
    newPrice: {
        kiabi: 15,
        OVS: 20,
    }
}

async function pushData( {id, item, newPrice} ) {
    try {
        var document = await dataBase.findOne({id: id })
        if (document){
            for (const seller in newPrice) {
                const allPrice = document.list[item][seller]
                const l = allPrice.length;
                if (l === 0 || allPrice[l-1].price !== newPrice[seller] ){
                    allPrice.push( { price: newPrice[seller], time: new Date() } )
                }
            }
            await dataBase.replaceOne({ matchName: matchName }, document)
        }else{//create new document
            var newDocument = {
                id: id,
                date: new Date(),
                list: {
                    t_shirt: {
                        kiabi: [],
                        OVS: [],
                        ZARA: []
                    },
                    shoes: {
                        kiabi: [],
                        OVS: [],
                        ZARA: []
                    },
                    hat: {
                        kiabi: [],
                        OVS: [],
                        ZARA: []
                    },
                },
            }
            for (const seller in newPrice) {
                newDocument.list[item][seller].push( { price: newPrice[seller], time: new Date() } )
            }
            try {
                await dataBase.create(newDocument)
            } catch (error) {
                if (error.code === 11000) {//duplicate key
                    pushData(id, item, newPrice)//retry
                }
            }
        }
    }catch (error){
        console.error(error);
    }
}

pushData(newData)

I would like to use only Mongoose .updateOne(), but I can't find the correct operators to create a working query.

0

There are 0 best solutions below