Подтвердить что ты не робот

Массив с уникальными значениями по всем документам одной коллекции

Ситуация: У меня есть несколько документов одного и того же набора (счет), каждый из которых имеет атрибут типа array (string) с именем uniquestrings.

Проблема: Каждая запись в uniquestrings должна быть уникальной по всем документам в mongodb. Похоже, что MongoDB/Mongoose не предлагает такой проверки (ни addToSet¹, ни index: {unique: true} ² решить проблему). Есть ли шаблон для реструктуризации моей схемы документов, чтобы убедиться, что сам mongodb может проверить его? В настоящий момент программное обеспечение проверяет его перед обновлением документа.

например.

account {
  _id: 111,
  uniquestrings: ["a", "b", "c"]
}

account {
  _id: 222,
  uniquestrings: ["d", "e", "f"]
}

например. предотвратите account(222).uniquestrings.push("a");, выбросив дублирующую ошибку из mongo.

¹ Уникальности в массиве недостаточно. ² Каждый элемент массива должен быть уникальным в коллекции

Update1:

Другие примеры. Затронутая запись схемы выглядит следующим образом:

var Account = new Schema({
    ...
    uniquestrings: [{type: String, index: {unique: true}}]
    ...
});

Теперь при создании 4 учетных документов. Я хочу, чтобы только 1 и 2 были в порядке, и отдых должен потерпеть неудачу.

var accountModel1 = new Account.Model({uniquestrings: ["a", "b"]});
accountModel1.save(); // OK
var accountModel2 = new Account.Model({uniquestrings: ["c", "d"]});
accountModel2.save(); // OK
var accountModel3 = new Account.Model({uniquestrings: ["c", "d"]});
accountModel3.save(); // FAIL => Not unique, so far so good
var accountModel4 = new Account.Model({uniquestrings: ["X", "d"]});
accountModel4.save(); // OK => But i Want this to faile because "d" is alreay in use.
4b9b3361

Ответ 1

Возможно, возможно, если вы захотите сохранить уникальные значения в другой коллекции. Он будет структурирован следующим образом:

{ "uniquestring" : "a", "account" : 111 }
{ "uniquestring" : "b", "account" : 111 }
{ "uniquestring" : "c", "account" : 111 }
{ "uniquestring" : "d", "account" : 222 }
{ "uniquestring" : "e", "account" : 222 }
{ "uniquestring" : "f", "account" : 222 }

Я не эксперт в Mongoose, но я считаю, что вы можете определить Модели для объединения коллекций вместе с полем учетной записи здесь, ссылающимся на поле _id коллекции учетных записей.

Теперь вы можете обеспечить уникальность с помощью простого индекса:

db.uniquestrings.createIndex( { "uniquestring" : 1 } , { unique : true } )

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

Редактирование PS приветствуется от кого-либо, у кого более подробные знания о том, как реализовать и использовать такие модели в мангусте.

Ответ 2

В соответствии с этот MongoDB Doc, не существует способа заставить MongoDB применять уникальную политику индекса в рамках одного документа, но есть способ принудительного исполнения в отдельных документах.

db.collection.createIndex("a.b");

... обеспечит уникальность для них на a.b...

db.collection.insert({ a: [{b: 1}] });
db.collection.insert({ a: [{b: 1}] });

... но не будет обеспечивать уникальность для этого...

db.collection.insert({ a: [{b: 1},{b: 1}] ]);

... НО, если вы строго используете $addToSet с индексом...

db.collection.upsert({ $addToSet: { a: { b: 1 } } });

... и вы ставите компромисс, не создавая исключение, а скорее upsert спокойно игнорирует дубликат, который не то, что вы хотите, но ближе.

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

Теперь, чтобы добиться того, что ваш запрос с помощью собственных запросов MongoDB невозможен из коробки, но вы могли бы ensureIndex и использовать охватываемый запрос для поиска индексированного массива и выкидывания ошибки, если вы его найдете, в противном случае upsert, как указано выше.

Итак...

// Ensure index
db.collection.createIndex({ 'a.b': 1 });

// Test for existence and throws up if not unique
function insertUnique(newVal) {
  var exists = db.collection.find({'a.b': newVal});
  if (exists) {
    throw "Element is not unique in the collection: " + newVal;
  } else {
    db.collection.upsert({ $addToSet: { a: { b: 1 } } });
  }
}

// Use it later...
try {
  insertUnique(1);
  insertUnique(1); // it should barf
} catch (e) {
  console.warn(e);
}

Наконец, в зависимости от того, какой клиент вы используете, вы можете продлить прототип (в JS) с помощью метода insertUnique, и вскоре вы забудете, что вы не могли бы этого сделать с самого начала.