Search code examples
mongodbmongoosemongodb-querymongodb-update

Replace field value with first element of an array in the same document


I have two models

// Product model
const ProductSchema = {
  vendors: [{ type: Schema.Types.ObjectId, ref: 'Vendor' }],
  mainVendor: { type: Schema.Types.ObjectId, ref: 'Vendor' },
}
// Vendor model
const VendorSchema = { ... }

When I delete a Vendor, I want all Products with mainVendor field of deleted Vendor's _id to be replaced with the first vendor of vendors array. If vendors array is empty, I want mainVendor to be set to null.

Say I have Product

const product = {
  mainVendor: 'mainVendorObjectId'
  vendors: ['secondVendorObjectid', 'thirdVendorObjectId']
}

When I delete Vendor with mainVendorObjectId _id, I want my product to be

const product = {
  mainVendor: 'secondVendorObjectId',
  vendors: ['thirdVendorObjectId']
}

If I have a product with empty vendors array

const product = {
  mainVendor: 'mainVendorObjectId',
  vendors: []
}

After deleting Vendor with mainVendorObjectId _id I want my product to be like

const product = {
  mainVendor: null,
  vendors: []
}

I want to run it in post hook.
What I have now

VendorSchema.post('findOneAndDelete', async function (res: TVendorModel) {
    try {
        const products = await ProductModel.updateMany(
            { mainVendor: res._id },
            { $expr: { $set: { mainVendor: '$vendors.0' } } }
        );
    } catch (error) {
        console.error(error);
    }
});

but it doesn't work and it won't set mainVendor to null if vendors array is empty.


Solution

  • A bit long query, but you can try with Update with aggregation pipeline.

    With $cond operator to check whether vendors is an empty array, if yes set null, else take the first value from the vendors array to mainVendor field.

    For the vendors field, it does the same concept as mainVendor field, the outcome will be different in removing the first item from vendors array.

    db.collection.update({
      mainVendor: "mainVendorObjectId"
    },
    [
      {
        $set: {
          mainVendor: {
            $cond: {
              if: {
                $eq: [
                  "$vendors",
                  []
                ]
              },
              then: null,
              else: {
                $first: "$vendors"
              }
            }
          },
          vendors: {
            $cond: {
              if: {
                $eq: [
                  "$vendors",
                  []
                ]
              },
              then: [],
              else: {
                $slice: [
                  "$vendors",
                  1,
                  {
                    $size: "$vendors"
                  }
                ]
              }
            }
          }
        }
      }
    ],
    {
      multi: true
    })
    

    Sample Mongo Playground