@JennyMok Если вы «попробовали», вам понадобится более 5 минут, чтобы на самом деле запустить примеры и понять их. Не "вишня"! Эту концепцию вы не понимаете, и какой-то приятный человек нашел время, чтобы написать необходимые лекционные заметки и упражнения для вас. Садись и решай это. Код, который я дал вам, демонстрирует, что делать. Запустить его! Узнать его! «Тогда» попробуйте применить только к вашему использованию. Но только когда ты это понимаешь. «Вдохни» означает, что мне действительно не нужно получать уведомления от вас каждые две минуты.

у выполнить массовую вставку (массив объектов) в мой документ, но я хочу предотвратить дублирование записей, не могу найти способ сделать это с помощью insertMany.

const Song = require('../models/song');
Song.insertMany([{id:1, name:"something"},{id:2, name:"something else"])
    .then((result) => {
      res.json({
        result
      })
    })

Вышеупомянутый код работал, но если запись такая же, она все равно будет вставлена.

 Neil Lunn07 нояб. 2017 г., 04:03
Здесь на самом деле есть четкая разница, потому что_id является фактическим первичным ключом, и в то время как мангуст позволяет вам «сойти с рук» с помощьюid в качестве «псевдонима» к этому в большинстве случаев это не относится кinsertMany(), Поскольку в вашей схеме фактически отсутствует такое свойство, оно будет «отброшено», и, следовательно, не имеет значения, указали ли вы одно и то же значение или нет, поскольку оно никогда не записывает. Но на самом деле картина гораздо сложнее, чем эта простая ошибка.
 Jenny Mok06 нояб. 2017 г., 17:18
@chade_ Я пробовал, пробовал хотя бы час, обновил мой вопрос кодом.

Ответы на вопрос(1)

ых, где задействован «уникальный ключ», из которых_id (псевдоним Мангуста какid, но игнорируетсяinsertMany() так что вы должны быть осторожны), но есть гораздо большая история, что выдействительно нужно знать.

Основная проблема здесь заключается в том, что как "мангуст" реализацияinsertMany() так же как и лежащий в основе драйвер в настоящее время немного «расточен», мягко говоря. В этом есть некоторая несогласованность в том, как драйвер передает ответ об ошибке в «массовых» операциях, и это на самом деле усугубляется тем, что «мангуст» на самом деле не «ищет в нужном месте» фактическую информацию об ошибке.

«Быстрая» часть, которую вам не хватает, это добавление{ ordered: false } на «Навальный» операции которого.insertMany() просто оборачивает вызов. Установка этого параметра гарантирует, что «пакет» запросов фактически передается «полностью» и не останавливает выполнение при возникновении ошибки.

Но так как «mongoose» не очень хорошо справляется с этим (и драйвер не «последовательно»), нам на самом деле нужно искать возможные «ошибки» в «ответе», а не результат «ошибки» основного обратного вызова.

В качестве демонстрации:

const mongoose = require('mongoose'),
      Schema = mongoose.Schema;

mongoose.Promise = global.Promise;
mongoose.set('debug',true);

const uri = 'mongodb://localhost/test',
      options = { useMongoClient: true };

const songSchema = new Schema({
  _id: Number,
  name: String
});

const Song = mongoose.model('Song', songSchema);

function log(data) {
  console.log(JSON.stringify(data, undefined, 2))
}

let docs = [
  { _id: 1, name: "something" },
  { _id: 2, name: "something else" },
  { _id: 2, name: "something else entirely" },
  { _id: 3, name: "another thing" }
];

mongoose.connect(uri,options)
  .then( () => Song.remove() )
  .then( () =>
    new Promise((resolve,reject) =>
      Song.collection.insertMany(docs,{ ordered: false },function(err,result) {
        if (result.hasWriteErrors()) {
          // Log something just for the sake of it
          console.log('Has Write Errors:');
          log(result.getWriteErrors());

          // Check to see if something else other than a duplicate key, and throw
          if (result.getWriteErrors().some( error => error.code != 11000 ))
            reject(err);
        }
        resolve(result);    // Otherwise resolve
      })
    )
  )
  .then( results => { log(results); return true; } )
  .then( () => Song.find() )
  .then( songs => { log(songs); mongoose.disconnect() })
  .catch( err => { console.error(err); mongoose.disconnect(); } );

Или, возможно, немного лучше, так как текущий LTS node.js имеетasync/await:

const mongoose = require('mongoose'),
      Schema = mongoose.Schema;

mongoose.Promise = global.Promise;
mongoose.set('debug',true);

const uri = 'mongodb://localhost/test',
      options = { useMongoClient: true };

const songSchema = new Schema({
  _id: Number,
  name: String
});

const Song = mongoose.model('Song', songSchema);

function log(data) {
  console.log(JSON.stringify(data, undefined, 2))
}

let docs = [
  { _id: 1, name: "something" },
  { _id: 2, name: "something else" },
  { _id: 2, name: "something else entirely" },
  { _id: 3, name: "another thing" }
];

(async function() {

  try {
    const conn = await mongoose.connect(uri,options);

    await Song.remove();

    let results = await new Promise((resolve,reject) => {
      Song.collection.insertMany(docs,{ ordered: false },function(err,result) {
        if (result.hasWriteErrors()) {
          // Log something just for the sake of it
          console.log('Has Write Errors:');
          log(result.getWriteErrors());

          // Check to see if something else other than a duplicate key, then throw
          if (result.getWriteErrors().some( error => error.code != 11000 ))
            reject(err);
        }
        resolve(result);    // Otherwise resolve

      });
    });

    log(results);

    let songs = await Song.find();
    log(songs);

  } catch(e) {
    console.error(e);
  } finally {
    mongoose.disconnect();
  }


})()

В любом случае вы получите тот же результат, показывающий, что записи продолжаются и что мы уважительно «игнорируем» ошибки, связанные с «дублирующим ключом» или иначе известные как код ошибки11000, «Безопасная обработка» заключается в том, что мы ожидаем такие ошибки и отбрасываем их, ища наличие «других ошибок», на которые мы могли бы просто обратить внимание. Мы также видим, что остальная часть кода продолжается и перечисляет все документы, фактически вставленные путем выполнения последующих.find() вызов:

Mongoose: songs.remove({}, {})
Mongoose: songs.insertMany([ { _id: 1, name: 'something' }, { _id: 2, name: 'something else' }, { _id: 2, name: 'something else entirely' }, { _id: 3, name: 'another thing' } ], { ordered: false })
Has Write Errors:
[
  {
    "code": 11000,
    "index": 2,
    "errmsg": "E11000 duplicate key error collection: test.songs index: _id_ dup key: { : 2 }",
    "op": {
      "_id": 2,
      "name": "something else entirely"
    }
  }
]
{
  "ok": 1,
  "writeErrors": [
    {
      "code": 11000,
      "index": 2,
      "errmsg": "E11000 duplicate key error collection: test.songs index: _id_ dup key: { : 2 }",
      "op": {
        "_id": 2,
        "name": "something else entirely"
      }
    }
  ],
  "writeConcernErrors": [],
  "insertedIds": [
    {
      "index": 0,
      "_id": 1
    },
    {
      "index": 1,
      "_id": 2
    },
    {
      "index": 2,
      "_id": 2
    },
    {
      "index": 3,
      "_id": 3
    }
  ],
  "nInserted": 3,
  "nUpserted": 0,
  "nMatched": 0,
  "nModified": 0,
  "nRemoved": 0,
  "upserted": [],
  "lastOp": {
    "ts": "6485492726828630028",
    "t": 23
  }
}
Mongoose: songs.find({}, { fields: {} })
[
  {
    "_id": 1,
    "name": "something"
  },
  {
    "_id": 2,
    "name": "something else"
  },
  {
    "_id": 3,
    "name": "another thing"
  }
]

Так почему этот процесс? Причина в том, что базовый вызов на самом деле возвращает обаerr а такжеresult как показано в реализации обратного вызова, но есть несоответствие в том, что возвращается. Основная причина для этого заключается в том, что вы действительно видите «результат», который имеет не только результат успешной операции, но и сообщение об ошибке.

Наряду с информацией об ошибкеnInserted: 3 с указанием того, сколько из «партии» действительно было написано. Вы можете в значительной степени игнорироватьinsertedIds здесь, так как этот конкретный тест связан с поставкой на самом деле_id ценности. В случае, когда другое свойство имело ограничение «уникальность», которое вызвало ошибку, единственными значениями здесь будут значения из фактической успешной записи. Немного вводит в заблуждение, но легко проверить и убедиться в этом.

Как уже говорилось, подвох - это «несоответствие», которое можно продемонстрировать на другом примере (async/await только для краткости перечисления):

const mongoose = require('mongoose'),
      Schema = mongoose.Schema;

mongoose.Promise = global.Promise;
mongoose.set('debug',true);

const uri = 'mongodb://localhost/test',
      options = { useMongoClient: true };

const songSchema = new Schema({
  _id: Number,
  name: String
});

const Song = mongoose.model('Song', songSchema);

function log(data) {
  console.log(JSON.stringify(data, undefined, 2))
}

let docs = [
  { _id: 1, name: "something" },
  { _id: 2, name: "something else" },
  { _id: 2, name: "something else entirely" },
  { _id: 3, name: "another thing" },
  { _id: 4, name: "different thing" },
  //{ _id: 4, name: "different thing again" }
];

(async function() {

  try {
    const conn = await mongoose.connect(uri,options);

    await Song.remove();

    try {
      let results = await Song.insertMany(docs,{ ordered: false });
      console.log('what? no result!');
      log(results);   // not going to get here
    } catch(e) {
      // Log something for the sake of it
      console.log('Has write Errors:');

      // Check to see if something else other than a duplicate key, then throw
      // Branching because MongoError is not consistent
      if (e.hasOwnProperty('writeErrors')) {
        log(e.writeErrors);
        if(e.writeErrors.some( error => error.code !== 11000 ))
          throw e;
      } else if (e.code !== 11000) {
        throw e;
      } else {
        log(e);
      }

    }

    let songs = await Song.find();
    log(songs);

  } catch(e) {
    console.error(e);
  } finally {
    mongoose.disconnect();
  }


})()

Все одно и то же, но обратите внимание на то, как здесь регистрируются ошибки:

Has write Errors:
{
  "code": 11000,
  "index": 2,
  "errmsg": "E11000 duplicate key error collection: test.songs index: _id_ dup key: { : 2 }",
  "op": {
    "__v": 0,
    "_id": 2,
    "name": "something else entirely"
  }
}

Обратите внимание, что информация об «успехе» отсутствует, хотя мы получаем то же самое продолжение списка, выполняя.find() и получить вывод. Это потому, что реализация действует только на «брошенную ошибку» в отклонении и никогда не проходит через фактическуюresult часть. Так что, хотя мы просилиordered: falseмы не получим информацию о том, что было выполнено, пока не завернем обратный вызов и не реализуем логику самостоятельно, как показано в первоначальных списках.

Другая важная «несогласованность» возникает, когда имеется «более одной ошибки». Так раскомментируя дополнительную ценность для_id: 4 дает нам:

Has write Errors:
[
  {
    "code": 11000,
    "index": 2,
    "errmsg": "E11000 duplicate key error collection: test.songs index: _id_ dup key: { : 2 }",
    "op": {
      "__v": 0,
      "_id": 2,
      "name": "something else entirely"
    }
  },
  {
    "code": 11000,
    "index": 5,
    "errmsg": "E11000 duplicate key error collection: test.songs index: _id_ dup key: { : 4 }",
    "op": {
      "__v": 0,
      "_id": 4,
      "name": "different thing again"
    }
  }
]

Здесь вы можете увидеть код "разветвленной" на наличиеe.writeErrors, который не существует, когда естьодин ошибка. В отличие от ранееresponse объект имеет какhasWriteErrors() а такжеgetWriteErrors() методы, независимо от наличия ошибок вообще. Так что это более согласованный интерфейс и причина, почему вы должны использовать его вместо проверкиerr Ответ один.

MongoDB 3.x Исправления драйверов

Это поведение фактически исправлено в следующей версии драйвера 3.x, которая должна совпадать с выпуском сервера MongoDB 3.6. Поведение меняется в том, чтоerr ответ больше похож на стандартresult, но конечно классифицируется какBulkWriteError ответ вместоMongoError который это в настоящее время.

До тех пор, пока это не будет выпущено (и, конечно же, пока эта зависимость и изменения не будут распространены на реализацию "mongoose"), тогда рекомендуется знать, что полезная информация находится вresult а такжене err, На самом деле ваш код, вероятно, должен искатьhasErrors() вresult а затем отступить, чтобы проверитьerr также, чтобы обслужить изменение, которое будет осуществлено в драйвере.

Примечание авторов: Большая часть этого контента и связанных с ним чтений на самом деле уже дан ответ здесьФункция insertMany () неупорядочена: правильный способ получить как ошибки, так и результат? а такжеMongoDB Node.js родной драйвер молча глотаетbulkWrite исключение, Но повторяю и уточняю здесь до тех пор, пока людям, наконец, не станет ясно, что именно так вы обрабатываете исключения в текущей реализации драйвера. И это действительно работает, когда вы смотрите в правильном месте и пишете свой код для соответствующей обработки.

 Jenny Mok07 нояб. 2017 г., 16:54
Длинный пост, я прочитал его, спасибо, чтобы указать на это, но каков ответ, кроме того, чтобы избежать insertMany?
 Jenny Mok08 нояб. 2017 г., 01:44
И что же мне делать? Вы бросаете открытый вопрос, не давая мне указания. Я могу сделать цикл и использовать findOneAndUpdate, но так ли это на самом деле? У меня нет проблем, чтобы заставить вещь просто работать, но я пытаюсь найти лучшее решение.
 Neil Lunn07 нояб. 2017 г., 20:28
@JennyMok Если это все, что вы поняли, вам действительно нужно потратить время на то, чтобы правильно прочитать, запустить примеры и понять, что на самом деле происходит. Мы, конечно, вовсе не «избегаем», так как это «подробно» показывает, как выделай это правильно, Короткий ответ: «Вы сделали это неправильно». Длинный ответ: «Сделайте это и поймите, почему вы получили ошибки и как их избежать».

Ваш ответ на вопрос