2016-04-04 11 views
0

Und die alte slash entkommt Bug hat uns mit einigen verkorksten Daten, etwa so:

{ 
    suggestions: [ 
     "ok", 
     "not ok /////////// ... 10s of KBs of this ... //////", 
    ] 
} 

Ich möchte nur diese schlechten Werte aus dem Array ziehen. Meine erste Idee war, $pull basierend auf einem regulären Ausdruck, die 4 „/“ Zeichen übereinstimmt, aber es scheint, dass reguläre Ausdrücke nicht auf große Strings zu arbeiten:

db.notes.count({suggestions: /\/\/\/\//}) // returns 0 
db.notes.count({suggestions: {$regex: "////"}}) // returns 0 

Meine nächste Idee war, eine $where Abfrage zu verwenden, um Dokumente zu finden, die suggestion Strings haben, die länger als 1000. Diese Abfrage funktioniert:

db.notes.count({ 
    suggestions: {$exists: true}, 
    $where: function() { 
     return !!this.suggestions.filter(function (item) { 
      return (item || "").length > 1000; 
     }).length 
    } 
}) 
// returns a plausible number 

Aber eine $where Abfrage kann nicht als Bedingung in einem $pull Update verwendet werden.

db.notes.update({ 
    suggestions: {$exists: true}, 
}, { 
    $pull: { 
     suggestions: { 
      $where: function() { 
       return !!this.suggestions.filter(function (item) { 
        return (item || "").length > 1000; 
       }).length 
      } 
     } 
    } 
}) 

wirft

WriteResult({ 
    "nMatched" : 0, 
    "nUpserted" : 0, 
    "nModified" : 0, 
    "writeError" : { 
     "code" : 81, 
     "errmsg" : "no context for parsing $where" 
    } 
}) 

ich die Ideen ausgehen. Muss ich über die gesamte Sammlung iterieren, und $set: {suggestions: suggestions.filter(...)} für jedes Dokument einzeln? Gibt es keinen besseren Weg, schlechte Werte aus einem Array großer Strings in MongoDB zu entfernen?

(Ich bin nur das „javascript“ Tag hinzufügen SO erhalten den Code korrekt zu formatieren)

+0

Wie viele Elemente müssen Sie aus dem Array entfernen? – styvane

+0

Weniger als 20 von jedem Array. Normalerweise 1. –

+2

Auch 'db.notes.count ({Vorschläge:/\/\ //})' sollte die Anzahl der Dokumente mit '/' unabhängig von der Länge der Zeichenfolge zurückgeben. Für große Zeichenfolgen sollten Sie das Filterargument für die Methode 'updateOne()' verwenden: 'db.notes.updateOne ({Vorschläge:/\/\ //}, {" $ pull ": {Vorschläge:/\/\ //}}) ' – styvane

Antwort

0

Die einfache Lösung in der Frage Kommentare gearbeitet haben darauf hingewiesen, sollte. Es funktioniert mit einem Testfall, der eine Wiederherstellung des ursprünglichen Problems darstellt. Regexes können auf große Strings passen, dort gibt es keine besonderen Einschränkungen.

db.notes.updateOne({suggestions: /\/\//}, { "$pull": {suggestions: /\/\//}}) 

Da dies nicht für mich arbeiten, landete ich mit oben gehen, was die Frage diskutiert:

langsam
db.notes.find({ 
    suggestions: {$exists: true} 
}).forEach(function(doc) { 
    doc.suggestions = doc.suggestions.filter(function(item) { 
     return (item || "").length <= 1000; 
    }); db.notes.save(doc); 
}); 

Es lief: alle Dokumente einzeln durch Filtern der Array-Elemente basierend auf Stringlänge Aktualisierung , aber das war in diesem Fall kein wirkliches Problem.

Verwandte Themen