HOWTO · MongoDB
Abfrage mit Zeichenfolgenlänge in MongoDB
In diesem Tutorial wird erläutert, wie Sie in MongoDB Abfragen mit Zeichenfolgenlänge durchführen.
Auf dieser Seite
Um MongoDB-Dokumente zu finden, deren Zeichenfolgenfeld genau fünf Unicode-Codepoints enthält, verwenden Sie $expr mit $strLenCP in find(): db.mydata.find({ $expr: { $eq: [{ $strLenCP: "$Name" }, 5] } }). Diese Kurzform setzt voraus, dass jedes Dokument ein Zeichenfolgenfeld Name hat. Eine weiter unten gezeigte abgesicherte Variante behandelt Felder mit unterschiedlichen Datentypen.
MongoDB-Dokumente anhand der Zeichenfolgenlänge abfragen
Verwenden Sie für den Vergleich der Ansätze dieselbe Sammlung und durchgehend dieselben Feldnamen. Das folgende eigenständige JavaScript-Beispiel legt sechs Beispieldokumente an und filtert sie lokal nach der Anzahl ihrer Codepoints. Es benötigt keine Datenbankverbindung und führt keine Abfrage auf einem MongoDB-Server aus.
Der Code und die angezeigten Bezeichnungen oder Ausgaben in diesem Abschnitt bleiben auf Englisch.
const documents = [
{ _id: 1, Name: "hello" },
{ _id: 2, Name: "world" },
{ _id: 3, Name: "abcdefgh" },
{ _id: 4, Name: "ijklmnop" },
{ _id: 5, Name: "apple" },
{ _id: 6, Name: "grape" }
];
const matches = documents.filter(document => [...document.Name].length === 5);
console.log(JSON.stringify(matches, null, 2));
[
{
"_id": 1,
"Name": "hello"
},
{
"_id": 2,
"Name": "world"
},
{
"_id": 5,
"Name": "apple"
},
{
"_id": 6,
"Name": "grape"
}
]
Bei diesen Daten enthalten die Dokumente 1, 2, 5 und 6 genau fünf Codepoints: hello, world, apple und grape. Die Dokumente 3 und 4 haben jeweils acht Codepoints.
Die Datenbankbefehle in diesem Artikel sind nicht ausgeführte Beispiele für die MongoDB-Shell. Für sie benötigen Sie eine Verbindung zu einem MongoDB-Server. Mit db.mydata.insertMany([{ _id: 1, Name: "hello" }, { _id: 2, Name: "world" }, { _id: 3, Name: "abcdefgh" }, { _id: 4, Name: "ijklmnop" }, { _id: 5, Name: "apple" }, { _id: 6, Name: "grape" }]) legen Sie die Beispieldaten in einer neuen Sammlung mydata an. Verwenden Sie eine separate Beispielsammlung, damit keine Konflikte mit bereits vorhandenen _id-Werten entstehen.
Mit $where nach der Zeichenfolgenlänge filtern
Der Abfrageoperator $where wertet JavaScript auf dem Server aus. Die Dokumentation beschreibt Einschränkungen bei der Bereitstellung und weist darauf hin, dass serverseitiges Scripting aktiviert sein muss. Wenn serverseitiges JavaScript verfügbar ist, können Sie die Beispieldaten mit db.mydata.find({ $where: function () { return typeof this.Name === "string" && this.Name.length === 5; } }) filtern.
Die Typprüfung überspringt fehlende, auf null gesetzte und nicht als Zeichenfolge vorliegende Werte. Ersetzen Sie === 5 durch > 5, um nach einer Länge von mehr als fünf zu filtern. JavaScripts .length zählt UTF-16-Codeeinheiten: Ein Emoji außerhalb der Basic Multilingual Plane belegt zwei Einheiten. Daher liefert dieser Ansatz bei der ASCII-Beispielmenge dieselben Ergebnisse wie die anderen Beispiele, ist aber kein allgemeiner Ersatz für das Zählen von Codepoints. Verwenden Sie $expr, wenn Sie die Bedingung ohne serverseitiges JavaScript ausdrücken möchten.
$expr und $strLenCP in find() verwenden
Mit dem $expr-Operator kann find() Aggregationsausdrücke auswerten. $strLenCP zählt Unicode-Codepoints; $eq vergleicht diese Anzahl mit dem Zielwert. Ersetzen Sie $eq durch $gt, um Zeichenfolgen mit mehr als fünf Codepoints zu finden, oder durch $gte, wenn fünf eingeschlossen werden sollen.
Wie die Dokumentation zu $strLenCP erklärt, muss der Eingabewert zu einer Zeichenfolge aufgelöst werden; fehlende oder auf null gesetzte Werte führen zu einem Fehler. Wenn Name einen anderen Datentyp haben kann, verwenden Sie einen bedingten Ausdruck:
db.mydata.find({ $expr: { $cond: [{ $eq: [{ $type: "$Name" }, "string"] }, { $eq: [{ $strLenCP: "$Name" }, 5] }, false] } })
$cond wertet den Längenvergleich nur für Zeichenfolgen aus und gibt andernfalls false zurück; siehe die Dokumentation zu $cond. Eine leere Zeichenfolge hat die Länge null. Ein fehlendes oder auf null gesetztes Feld wird übersprungen und nicht wie eine leere Zeichenfolge behandelt. Verlassen Sie sich nicht darauf, dass eine separate, mit $and verknüpfte Bedingung zuerst ausgewertet wird und $strLenCP vor ungeeigneten Eingaben schützt.
Codepoints unterscheiden sich von UTF-8-Bytes und sichtbaren Zeichen: Ein Buchstabe mit einem kombinierenden Akzent besteht aus zwei Codepoints. Wählen Sie die Zählweise, die Ihre Anwendung benötigt.
Die Links zur offiziellen Dokumentation dienen als Referenz; ihre aktuelle Erreichbarkeit und ihr Inhalt wurden hier nicht überprüft.
Für verschachtelte Felder ändern Sie den Ausdrucksverweis in einen Punktpfad wie "$parentField.childField" und passen den Typvergleich ebenfalls an. Wenn Sie nach mehreren Feldern filtern, verknüpfen Sie vollständige Bedingungen mit $and oder $or.
Mit einer Aggregationspipeline nach der Zeichenfolgenlänge filtern
Verwenden Sie eine Aggregationspipeline, wenn das Filtern Teil einer umfassenderen Transformation ist. Für die Beispielsammlung wählt diese $match-Stufe die beiden Zeichenfolgen mit jeweils acht Codepoints aus:
db.mydata.aggregate([{ $match: { $expr: { $eq: [{ $strLenCP: "$Name" }, 8] } } }])
Die passenden Dokumente sind { _id: 3, Name: "abcdefgh" } und { _id: 4, Name: "ijklmnop" }. Dieses Beispiel setzt wie die Beispieldaten Zeichenfolgen als Eingaben voraus. Bei gemischten Datentypen ersetzen Sie den Wert von $expr durch den abgesicherten $cond-Ausdruck aus dem vorherigen Abschnitt und setzen den Zielwert auf acht. Mit $project können Sie die passenden Dokumente umformen, mit $group zusammenfassen.
Eine feste Zeichenfolgenlänge mit einem regulären Ausdruck abgleichen
Für die einzelnen Zeichenfolgen aus ASCII-Buchstaben in diesem Beispiel verwenden Sie db.mydata.find({ Name: { $regex: "^.{5}$" } }). Die Anker begrenzen den Treffer, und {5} wiederholt den Punkt fünfmal. Damit werden die Dokumente 1, 2, 5 und 6 ausgewählt.
Die offizielle Dokumentation zu $regex erläutert die passenden Abgleichoptionen und Anker. Für beliebige Texte muss dieses Muster jedoch eingeordnet werden: Der Punkt schließt normalerweise Zeilenumbrüche aus, und $ kann vor einem abschließenden Zeilenumbruch matchen. Ein Regex-Feldprädikat kann außerdem ein Zeichenfolgenelement innerhalb eines Arrays finden. Wenn Sie ein einzelnes Zeichenfolgenfeld und eine ausdrückliche Zählung der Codepoints benötigen, verwenden Sie vorzugsweise die abgesicherte $strLenCP-Abfrage. Wählen Sie Regex, wenn Zeichenmuster Teil der Aufgabe sind, und messen Sie die Leistung für Ihre eigene Arbeitslast, bevor Sie Entscheidungen zu Effizienz oder Indizes treffen.