简体   繁体   中英

Sequelize upsert

i need to get the id for the inserted/updated record when using .upsert() in sequelize.

right now .upsert() returns a boolean indicating whether the row was created or updated.

return db.VenueAddress.upsert({
            addressId:address.addressId,
            venueId: venue.venueId,
            street: address.street,
            zipCode: address.zipCode,
            venueAddressDeletedAt: null
        }).then(function(test){
            //test returned here as true or false how can i get the inserted id here so i can insert data in other tables using this new id?
        });

I don't think that returning the upserted record was available when the OP asked this question, but it has since been implemented with this PR . As of Sequelize v4.32.1 , you can pass a boolean returning as a query param to select between returning an array with the record and a boolean, or just a boolean indicating whether or not a new record was created.

You do still need to provide the id of the record you want to upsert or a new record will be created.

For example:

const [record, created] = await Model.upsert(
  { id: 1, name: 'foo' }, // Record to upsert
  { returning: true }     // Return upserted record
);

I wanted upsert to return the created or updated object. It doesn't because only PGSQL supports it directly, apparently.

So I created a naive implementation that will - probably in a non-performant way, and possibly with all sorts of race conditions, do that:

Sequelize.Model.prototype.findCreateUpdate = function(findWhereMap, newValuesMap) {
  return this.findOrCreate({
    where: findWhereMap, 
    defaults: findWhereMap
  })
  .spread(function(newObj, created) {
    // set:
    for(var key in newValuesMap) {
      newObj[key] = newValuesMap[key];
    }

    return newObj.save();
  });
};

Usage when trying to create/update a move in a game (contrived example alert!):

models.Game
.findOne({where: {gameId: gameId}})
.then(function(game) {
  return db.Move.findCreateUpdate(
    {gameId: gameId, moveNum: game.moveNum+1}, 
    {startPos: 'kr4', endPos: 'Kp2'}
  );
});

This is what worked for me:

Model.upsert({
    title:your title,
    desc:your description,
    location:your locations
}).then(function (test) {
    if(test){
        res.status(200);
        res.send("Successfully stored");
    }else{
        res.status(200);
        res.send("Successfully inserted");
    }
})

It will check db to find based on your primary key. If it finds then, it will update the data otherwise it will create a new row/insert into a new row.

i know this is an old post, but in case this helps anyone

const upsert = async (model: any, values: any, condition: any): Promise<any> => {
  const obj = await model.findOne({ where: condition })
  if (obj) {
    // only do update is value is different from queried object from db
    for (var key in values) {
      const val = values[key]
      if (parseFloat(obj[key]) !== val) {
        obj.isUpdatedRecord = true
        return obj.update(values)
      }
    }
    obj.isUpdatedRecord = false
    return obj

  } else {
    // insert
    const merged = { ...values, ...condition }
    return model.create(merged)
  }
}

It isn't using upsert, but .bulkCreate has an updateOnDuplicate parameter, which allows you to update certain fields (instead of creating a new row) in the event that the primary key already exists.

MyModel.bulkCreate(
  newRows,
  {
    updateOnDuplicate: ["venueId", ...]
  }
)

I believe this returns the resulting objects, and so I think this might enable the functionality you're looking for?

janmeier said:

This is only supported by postgres, so to keep the API consistent across dialects this is not possible.

please see : https://github.com/sequelize/sequelize/issues/3354

I believe my solution is the most up to date with most minimal coding.

const SequelizeModel = require('sequelize/lib/model')
SequelizeModel.upsert = function() {
  return this.findOne({
    where: arguments[0].where
  }).then(obj => {
    if(obj) {
      obj.update(arguments[0].defaults)
      return
    }
    return this.create(arguments[0].defaults)
  })
}

I know this is an old post, but in case this helps anyone...you can get the returned id or any other value in this way based on OP data.

   var data = {
    addressId:address.addressId,
    venueId: venue.venueId,
    street: address.street,
    zipCode: address.zipCode,
    venueAddressDeletedAt: null
   }

   const result = await db.VenueAddress.upsert(data, { returning: true });
   console.log('resulttttttttttttttttt =>', result)
   
  res.status(200).json({ message: 'Your success message', data: result[0].id});

Noticed how I passed { returning: true } and get the value from the result data.

Which I myself resolved as follows:

return db.VenueAddress.upsert({
        addressId:address.addressId,
        venueId: venue.venueId,
        street: address.street,
        zipCode: address.zipCode,
        venueAddressDeletedAt: null
    },{individualHooks: true}).then(function(test){ 
        // note individualHooks
    });

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM