Search code examples
mongodbmongooseinsert-update

mongodb update one with upset is not working as expected


This is my mongoose schema.

const CurrencySchema = new mongoose.Schema({
    source: { type: String, uppercase: true, required: true, minlength: 3, maxlength: 3, trim: true },
    convert: { type: String, uppercase: true, required: true, minlength: 3, maxlength: 3, trim: true },
    exchange: [
        {
            year: { type: Number, required: true, min: [2000, 'Year can be only positive value'], },
            rate: { type: Number, min: [0, 'Exchange rate can be only positive value'], required: true }
        }
    ],
    created_by: { type: String, max: 100 },
    updated_by: { type: String, max: 100 }

}, { versionKey: false, timestamps: { createdAt: 'created_at', updatedAt: 'updated_at' } });

I have to update this collection with the following condition.

I will send source, convert, year, rate in a routine.

  1. If source and convert is not available in the collection, it should create a document with exchange rate and year
  2. If source and convert is available, but year is not available in the exchange list, then it should push {year, rate} object into the exchange list.
  3. If year is available in the exchange list, then it should update the rate of that year.

My existing query is,

const response = await Currencies.updateOne(
            { source, convert },
            [{
                $set: {
                    exchange: {
                        $cond: [
                            { $in: [year, "$exchange.year"] },
                            {
                                $map: {
                                    input: "$exchange",
                                    in: {
                                        $cond: [
                                            { $eq: ["$$this.year", year] },
                                            {
                                                year: "$$this.year",
                                                rate: rate
                                            },
                                            "$$this"
                                        ]
                                    }
                                }
                            },
                            { $concatArrays: ["$exchange", [{ year: year, rate: rate }]] }
                        ]
                    }
                }
            }],
            {
                upsert: true
            }
        )

When I try to pass this input {source: EUR, convert: XCD, year: 2022, rate: 3.5}, the query throws $in requires an array as a second argument, found: missing error. When source and convert is not available in the db.

How can I fix this with my all conditions?


Solution

  • You can check if some field is not array and if so - simply assign some value to that field.

    const response = await Currencies.updateOne(
        { source, convert },
        [{
            $set: {
                exchange: {
                    $cond: {
                        if: {$isArray: "$exchange"},
                        then: {
                            $cond: [
                                { $in: [year, "$exchange.year"] },
                                {
                                    $map: {
                                        input: "$exchange",
                                        in: {
                                            $cond: [
                                                { $eq: ["$$this.year", year] },
                                                {
                                                    year: "$$this.year",
                                                    rate: rate
                                                },
                                                "$$this"
                                            ]
                                        }
                                    }
                                },
                                { $concatArrays: ["$exchange", [{ year: year, rate: rate }]] }
                            ]
                        },
                        else: [{ year: year, rate: rate }]
                    }
                }
            }
        }],
        {
            upsert: true
        }
    )