Mongodb версия 3+: как вставить новый документ, только если он не существует, и получить результат - PullRequest
0 голосов
/ 06 октября 2019

Я испробовал десятки решений, и ни одно из них не сработало, и большинство из них устарели.

У меня есть коллекция с такими документами:

    _id: 5d99ef3285c93711828cd15d
    code: 1234
    name: "Foo"
    surname: "Bar"
    address: "That street"
    phone: 1234567

Я бы хотелвставлять новый документ, только если нет документа с таким же code.

Моя последняя попытка была такой:

const result = await db.collection('users').findOneAndUpdate(
    { code: user.code },
    {
        $setOnInsert: user,
    },
    {
        upsert: true,
    }
);

, но я получаю E11000 повторяющийся набор ошибок ключа ...

updateOne() возвращает ту же ошибку;update() устарело ...

Итак, как добавить только новый документ и получить результат (true, если документ был добавлен, или false, если он уже существует)?

Спасибо.

Ответы [ 6 ]

1 голос
/ 07 октября 2019

Насколько я знаю,

с $ set и $ setOnInsert, мы можем не обновить / вставить одно и то же поле.

т.е. $set и $ setOnInsert должны быть взаимоисключающими.

Работает при обновлении документа, но выдает исключение при вставке документа.

В случае обновления $ setOnInsertбудет игнорироваться.

В случае вставки оба будут выполнены.

Я думаю, что решение будет,

использовать returnNewDocument и иметь одинполе в схеме isUpdated по умолчанию равно false.

Примечание:

убедитесь, что всякий раз, когда вы используете операцию «вставки» в коллекцию, вы не добавляете isUpdated, который будет установлен в значение false, или в значение false. .

сформировать запрос, подобный

db.collection('users').findOneAndUpdate(
    { code: user.code },
    {
        $set: user,          // which has user.isUpdated set to true
    },
    {
        upsert: true,
        returnNewDocument: false, // (by default it is false only)
    }
);

С этой логикой

Итак, давайте пошагово,

  1. Если документ doc1 отсутствует, он будет вставлен, и mongo вернет ответ null. Вы узнаете, что это Вставлено .

  2. Если документ doc2 присутствует (учитывая, что эта логика не применяется к ранее вставленному документу doc2 перед и isUpdated поле отсутствует в doc2), оно будет выполнять $ set, поэтому в возвращаемом курсоре это поле отсутствует, т. Е. undefined, поэтому, как вы знаете, оно обновлено .

  3. допустим, мы снова запускаем тот же запрос для doc1 (который присутствует, и мы применили нашу новую логику), затем есть два случая

    a. оно будет обновлено и в курсоре у нас будет isUpdated, равный false.

    b. оно будет обновлено и в курсоре у нас будет isUpdated, равное true.

    В обоих случаях вы знаете, что это Обновлено

Я думаю, что этот подход должен решить вашу проблему.

Пожалуйста, поделитесь, если это поможет вам, или вы нашли какое-либо другое решение.

ОБНОВЛЕНИЕ

Фактически

Вам даже не нужно другое поле isUpdated, без этого поля это должно работать с той же логикой.

т.е. если курсоримеет значение null, а затем вставляется, если не является null, то обновляется.

0 голосов
/ 06 октября 2019

Попробуйте это

   db.collection("users").findOne({ code: user.code }, (err, data) => {
      if (data) {
        return res.send(false);
      } else {
        // a document
        var user = new User({
          code: code,
          name: "Foo",
          surname: "Bar",
          address: "That street",
          phone: 1234568
        });

        // save model to database
        user.save(function(err, book) {
          if (err) return console.error(err);
          return res.send(true);
        });
      }
    });
0 голосов
/ 06 октября 2019
 Users.findOneAndUpdate({code:user.code}, {upsert: true, new: true, setDefaultsOnInsert: true }, function(error, result) { if (error) return; // do something with the document }).

Я думаю, что это будет работать. Дайте нам знать, если у вас есть какие-либо вопросы.

0 голосов
/ 06 октября 2019

Вы можете использовать findOne, чтобы увидеть, существует ли пользователь с таким кодом первым

const result = await db.collection('users')
    .findOne({ code: user.code });

if( result ){ 
  return res
      .status(400)
      .json({ errors: [{ msg: 'User already exists' }] });
}
//create 
user = new User({
     code = code, 
     name = name, 
     foo = foo
)}
//save
user.save();   
res.json(user);
0 голосов
/ 06 октября 2019

Вы можете просто обернуть запрос блоком try / catch, чтобы поймать ошибку. Затем верните false при возникновении этого исключения.

0 голосов
/ 06 октября 2019

Вы все еще можете выполнить запрос, подобный этому;

document = db.collection('users').findOne({code:userCode});
if(document == null){
     //document  doesn't exists so you can use insertOne
}
else{
// document exists, sou you can update
}

, он не будет эффективным, но он сделает свою работу.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...