2014-09-01 2 views
1

У меня есть документы, как это:группа по и удаления документов, на основе размера массива поля

{ 
    "_id" : ObjectId("53bcedc39c837bba3e1bf1c2"), 
    id : "abc1", 
    someArray: [ 1 , 10 , 11] 
} 

{ 
    "_id" : ObjectId("53bcedc39c837bba3e1bf1c4"), 
    id : "abc1", 
    someArray: [ 1 , 10] 
} 
... other similar documents with different Ids 

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

Аккумулятор $count не существует, поэтому я не вижу, как я могу использовать $group.

Кроме того, будет 1000 идентификаторов, которые имеют дубликаты, подобные этому, поэтому, если есть такая вещь, как массовая проверка/удаление, это было бы хорошо (возможно, глупый вопрос, извините, Mongo для меня все новенький!)

ответ

4

Удаление «дубликатов» - это процесс, и здесь нет простого способа как «идентифицировать» дубликаты, так и «удалять» их как единый оператор. Другой особенностью здесь является то, что формы запросов не могут «обычно» определять размер массива и, конечно же, не могут сортироваться по тому, где он еще не присутствует в документе.

Все случаи в основном сводятся к

  1. Определение перечня документов, которые «дублируют», а затем в идеале перебирая конкретный документ, который вы хотите удалить, или ближе к делу документ, который вы «доном 't "хотите удалить из возможных дубликатов.

  2. Обработка этого списка для фактического выполнения удалений.

Имея это в виду, вы, надеюсь, есть современная MongoDB 2,6 версии или выше, где вы можете получить курсор из метода aggregate. Вы также хотите Bulk Operations API доступны в следующих версиях для оптимальной скорости:

var bulk = db.collection.initializeOrderedBulkOp(); 
var counter = 0; 

db.collection.aggregate([ 
    { "$project": { 
     "id": 1, 
     "size": { "$size": "$someArray" } 
    }}, 
    { "$sort": { "id": 1, "size": -1 } }, 
    { "$group": { 
     "_id": "$id", 
     "docId": { "$first": "$_id" } 
    }} 
]).forEach(function(doc) { 
    bulk.find({ "id": doc._id, "_id": { "$ne": doc.docId }).remove(); 
    counter++; 

    // Send to server once every 1000 statements only 
    if (counter % 1000 == 0) { 
     bulk.execute(); 
     bulk = db.collection.initializeOrderedBulkOp(); // need to reset 
    } 
}); 

// Clean up results that did not round to 1000 
if (counter % 1000 != 0) 
    bulk.execute(); 

Вы все еще можете сделать почти то же самое с более старыми версиями MongoDB, но результат от .aggregate() должен находиться под 16Мб, которая является пределом BSON. Это все равно должно быть много, но с более старыми версиями вы также можете выводить на коллекцию с помощью mapReduce.

Но для общей реакции агрегации вы получаете массив результатов, и у вас также нет других методов convienience для нахождения размера массива. Так немного больше работы:

var result = db.collection.aggregate([ 
    { "$unwind": "$someArray" }, 
    { "$group": { 
     "_id": "$id", 
     "id": { "$first": "$id" }, 
     "size": { "$sum": 1 } 
    }}, 
    { "$sort": { "id": 1, "size": -1 } }, 
    { "$group": { 
     "_id": "$id", 
     "docId": { "$first": "$_id" } 
    }} 
]); 

result.result.forEach(function(doc) { 
    db.collection.remove({ "id": doc._id, "_id": { "$ne": doc.docId } }); 
}); 

Так нет курсора для больших результатов и не массовые операций так каждый «удалить» не должны быть отправлены на сервер по отдельности.

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

Как примечание, если «размер» массивов является чем-то важным для вас с такой целью, как «сортировка», то ваш лучший помощник должен поддерживать этот «размер» как другое свойство вашего документа, чтобы оно делало эти операции легче без необходимости «подсчитывать» то, что делается здесь.

Смежные вопросы