Для относительно небольших данных, вы можете достичь выше, используя структуру агрегации, где вы создаете новый массив с различными значениями бренда с помощью оператора в $setUnion
в стадии $project
. Если массив содержит повторяющиеся записи, $setUnion
игнорирует дубликаты записей, а также порядок элементов.
После того, как вы получите новое поле различных марок, вам потребуется дополнительное поле для фильтрации документов во всей коллекции т.е. он проверяет, имеет ли данный массив уникальных элементов, используя ту же концепцию с оператором на $setUnion
. Используйте массив результатов из агрегированных документов обновить свою коллекцию итерируя курсор результатов, используя его forEach()
метода и обновление каждого документа следующим образом:
db.wholesalers.aggregate([
{
"$project": {
"distinctBrands": { "$setUnion": [ "$brands", [] ] },
"hasUniqueBrands": {
"$eq": [
{ "$size": "$brands" },
{ "$size": { "$setUnion": [ "$brands", [] ] } }
]
}
}
},
{ "$match": { "hasUniqueBrands": false } }
]).forEach(function(doc) {
db.wholesalers.update(
{ "_id": doc._id },
{ "$set": { "brands": doc.distinctBrands } }
)
})
Хотя это является оптимальным для небольших коллекций, производительность с большими коллекциями значительно сокращается, так как цикл через большой набор данных и отправка каждой операции обновления за запрос на сервер приводит к компьютерному штрафу.
Bulk()
API приходит на помощь и значительно повышает производительность, поскольку операции записи отправляются на сервер только один раз навалом. Эффективность достигается, поскольку метод не отправляет каждый запрос на запись на сервер (как и в текущем операторе обновления в цикле forEach()
), но только один раз в каждые 1000 запросов, что делает обновления более эффективными и быстрыми, чем в настоящее время.
Используя ту же концепцию выше с петлей forEach()
, чтобы создать партии, мы можем обновить коллекцию навалом следующим образом.
В этой демонстрации Bulk()
API доступен в MongoDB версии >= 2.6 and < 3.2
использует метод initializeUnorderedBulkOp()
выполняться параллельно, а также в недетерминированном порядке, операции записи в партиях:
var bulk = db.wholesalers.initializeUnorderedBulkOp(),
counter = 0; // counter to keep track of the batch update size
db.wholesalers.aggregate([
{
"$project": {
"distinctBrands": { "$setUnion": [ "$brands", [] ] },
"hasUniqueBrands": {
"$eq": [
{ "$size": "$brands" },
{ "$size": { "$setUnion": [ "$brands", [] ] } }
]
}
}
},
{ "$match": { "hasUniqueBrands": false } }
]).forEach(function(doc) {
bulk.find({ "_id": doc._id }).updateOne({
"$set": { "brands": doc.distinctBrands }
});
counter++; // increment counter
if (counter % 1000 == 0) {
bulk.execute(); // Execute per 1000 operations
// and re-initialize every 1000 update statements
bulk = db.wholesalers.initializeUnorderedBulkOp();
}
});
Следующий пример относится к новой версии MongoDB 3.2
, которая с тех пор устарела Bulk()
API и предоставил новый набор apis с использованием bulkWrite()
.
Он использует те же курсоры, как описаны выше, но и создает массивы с объемными операциями с использованием тех же forEach()
метод курсора, чтобы подтолкнуть каждый объемный документ на запись в массив. Поскольку команда записи не могут принимать не более 1000 операций, там нужно группировать операции, чтобы иметь максимум 1000 операций и повторно intialise массива, когда цикл попадет в 1000 итерации:
var bulkUpdateOps = [];
db.wholesalers.aggregate([
{
"$project": {
"distinctBrands": { "$setUnion": [ "$brands", [] ] },
"hasUniqueBrands": {
"$eq": [
{ "$size": "$brands" },
{ "$size": { "$setUnion": [ "$brands", [] ] } }
]
}
}
},
{ "$match": { "hasUniqueBrands": false } }
]).forEach(function(doc){
bulkUpdateOps.push({
"updateOne": {
"filter": { "_id": doc._id },
"update": { "$set": { "brands": doc.distinctBrands } }
}
});
if (bulkUpdateOps.length === 1000) {
db.wholesalers.bulkWrite(bulkUpdateOps);
bulkUpdateOps = [];
}
});
if (bulkUpdateOps.length > 0) { db.wholesalers.bulkWrite(bulkUpdateOps); }
вы хотите сделать это в Монго Shell ли? – Mahdi
Самый простой способ - написать скрипт, который обновит все ваши записи. И в будущем вы должны использовать оператор $ set для предотвращения дублирования. – Sabik