2015-03-04 14 views
6

Mam następujące zapytanie, aby znaleźć tagi   w polu nazwy i zastąpić je pustym miejscem - aby się ich pozbyć.
Łańcuchy nazw mogą mieć od 1 do wielu znaczników  , np.Znajdź i zamień łańcuchy w dokumentach Sprawnie

AA aa 
AA  aa 
AA   aa 
AA    aa 
AA AA aaaaaaaa 

... tak.

db.tests.find({'name':/.* .*/}).forEach(function(test){ 
     test.name = test.name.replace(" ",""); 
     db.tests.save(test); 
    }); 

    db.tests.find({'name':/.*  .*/}).forEach(function(test){ 
     test.name = test.name.replace("  ",""); 
     db.tests.save(test); 
    }); 

    db.tests.find({'name':/.*   .*/}).forEach(function(test){ 
     test.name = test.name.replace("   ",""); 
     db.tests.save(test); 
    }); 

Poza powtórzenie tego samego wzoru zapytania, jest lepszym rozwiązaniem do obsługi tego scenariusza, w zakresie mniejszym powielania i wyższej wydajności?

Odpowiedz

12

Z pewnością, jeśli wszystko, co chcesz zrobić, to odizolować   podmioty z tekstu, a następnie po prostu zrobić globalną mecz i zastąpić:

db.tests.find({ "name": /\ /g }).forEach(function(doc) { 
    doc.name = doc.name.replace(/ /g,""); 
    db.tests.update({ "_id": doc._id },{ "$set": { "name": doc.name } }); 
}); 

Więc nie ma potrzeby, aby napisać każdą kombinację, regex zastąpi bardzo pasujący do opcji /g. Możliwe, że użyjesz również /m dla wieloliniowości, twój łańcuch "nazwa" zawiera znaki nowej linii. Zobacz podstawowy regexer example.

Zaleca się również użycie $set w celu zmodyfikowania tylko tych pól, które naprawdę chcemy, a nie całego dokumentu. Jest mniejszy ruch i mniejsze prawdopodobieństwo nadpisania zmian, które mogły zostać wprowadzone przez inny proces od czasu odczytania dokumentu.

Idealnie byłoby użyć interfejsu API Operacji zbiorczych z wersją MongoDB w wersji 2.6 i nowszą. Pozwala to na aktualizacje do „partia”, więc nie jest jeszcze mniejszy ruch między klientem a serwerem:

var bulk = db.tests.initializeOrderedBulkOp(); 
var count = 0; 

db.tests.find({ "name": /\ /g }).forEach(function(doc) { 
    doc.name = doc.name.replace(/ /g,""); 
    bulk.find({ "_id": doc._id }) 
     .updateOne({ "$set": { "name": doc.name } }); 
    count++; 

    if (count % 1000 == 0) { 
     bulk.execute(); 
     bulk = db.tests.initializeOrderedBulkOp(); 
    } 
}); 

if (count % 1000 != 0) 
    bulk.execute(); 

To są twoje podstawowe sposoby, aby poprawić to. Niestety nie ma sposobu, aby instrukcja aktualizacji MongoDB użyła istniejącej wartości jako części wyrażenia aktualizacji w ten sposób, więc jedynym sposobem jest zapętlenie, ale możesz zrobić dużo, aby zmniejszyć operacje, jak pokazano.

+1

Nie trzeba uruchamiać zapytania aktualizacji $ set: można po prostu uruchomić db.tests.save (doc); – alexcasalboni

Powiązane problemy