web-dev-qa-db-fra.com

Sequelize upsert

j'ai besoin d'obtenir l'identifiant de l'enregistrement inséré/mis à jour lors de l'utilisation de .upsert() dans la suite.

en ce moment .upsert() renvoie un booléen indiquant si la ligne a été créée ou mise à jour.

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?
        });
20
Hussein Al-Far

Je ne pense pas que le retour de l'enregistrement renversé était disponible lorsque l'OP a posé cette question, mais il a depuis été implémenté avec ceci PR . Depuis Sequelize v4.32.1 , vous pouvez passer un booléen returning comme paramètre de requête pour choisir entre renvoyer un tableau avec l'enregistrement et un booléen, ou simplement un booléen indiquant si un nouvel enregistrement a été créé ou non.

Vous devez toujours fournir l'ID de l'enregistrement que vous souhaitez upsert ou un nouvel enregistrement sera créé.

Par exemple:

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

Je voulais qu'upsert retourne l'objet créé ou mis à jour. Ce n'est pas le cas, car seul PGSQL le prend en charge directement, apparemment.

J'ai donc créé une implémentation naïve qui - probablement d'une manière non performante, et éventuellement avec toutes sortes de conditions de concurrence, le fera:

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();
  });
};

Utilisation lors de la tentative de création/mise à jour d'un coup dans un jeu (exemple d'alerte artificielle!):

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

C'est ce qui a fonctionné pour moi:

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");
    }
})

Il vérifiera db pour trouver en fonction de votre clé primaire. S'il trouve alors, il mettra à jour les données sinon il créera une nouvelle ligne/insérera dans une nouvelle ligne.

5
Omar Faroque Anik

je sais que c'est un ancien poste, mais au cas où cela aiderait quelqu'un

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)
  }
}
3
Matthew Chung

janmeier a déclaré:

Ceci n'est supporté que par postgres, donc pour garder l'API cohérente entre les dialectes, ce n'est pas possible.

veuillez voir: https://github.com/sequelize/sequelize/issues/3354

2
Hussein Al-Far

Je crois que ma solution est la plus à jour avec le codage le plus minimal.

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)
  })
}
0
indospace.io