W MongoDB $substrBytes
Operator potoku agregacji zwraca podciąg ciągu w oparciu o określone indeksy bajtów zakodowanych w UTF-8.
Składnia
Składnia wygląda tak:
{ $substrBytes: [ <string expression>, <byte index>, <byte count> ] }
Gdzie:
<string expression>
jest ciągiem. Może to być dowolne prawidłowe wyrażenie, o ile prowadzi do łańcucha.<byte index>
jest miejscem, od którego zaczyna się podciąg. Może to być dowolne prawidłowe wyrażenie, pod warunkiem, że daje wynik nieujemnej liczby całkowitej lub liczby, która może być reprezentowana jako liczba całkowita.<byte count>
to liczba bajtów, przez które podciąg powinien być kontynuowany. Może to być dowolne prawidłowe wyrażenie, pod warunkiem, że daje wynik nieujemnej liczby całkowitej lub liczby, która może być reprezentowana jako liczba całkowita.
Przykład
Wyobraź sobie, że mamy kolekcję o nazwie tests
z następującym dokumentem:
{ "_id" : 1, "data" : "Red Firetruck" }
Możemy użyć $substrBytes
tak:
db.test.aggregate(
[
{ $match: { _id: { $in: [ 1 ] } } },
{
$project:
{
_id: 0,
data: 1,
result: { $substrBytes: [ "$data", 0, 3 ] }
}
}
]
)
Wynik:
{ "data" : "Red Firetruck", "result" : "Red" }
Indeks zaczyna się od zera, więc nasz podciąg zaczynał się na początku ciągu i trwał przez trzy bajty.
W tym przypadku używamy znaków angielskich, a każdy znak to jeden bajt. Ułatwia nam to policzenie liczby bajtów do wykorzystania.
Przeanalizujmy inny przykład:
db.test.aggregate(
[
{ $match: { _id: { $in: [ 1 ] } } },
{
$project:
{
_id: 0,
data: 1,
result_1: { $substrBytes: [ "$data", 4, 4 ] },
result_2: { $substrBytes: [ "$data", 8, 5 ] },
result_3: { $substrBytes: [ "$data", 8, 20 ] }
}
}
]
).pretty()
Wynik:
{ "data" : "Red Firetruck", "result_1" : "Fire", "result_2" : "truck", "result_3" : "truck" }
Zauważ, że w naszym trzecim wyniku określiliśmy więcej bajtów, niż było dostępnych, ale po prostu zwróciliśmy wszystkie znaki na koniec ciągu.
Znaki wielobajtowe
Niektóre znaki używają więcej niż jednego bajtu. Niektórzy używają dwóch, niektórzy trzech, a niektórzy nawet czterech.
Oto przykład dokumentu, który zawiera kilka symboli:
{ "_id" : 2, "data" : "©♡★✪☆" }
Każdy z tych znaków używa więcej niż jednego bajtu. Oznacza to, że musimy być ostrożni podczas wyodrębniania podciągu. Musimy mieć pewność, że nasz punkt wyjścia nie zaczyna się w połowie postaci. Jeśli tak, wystąpi błąd. Podobnie musimy upewnić się, że nasz punkt końcowy nie kończy się w połowie postaci.
Na razie zastosujmy $substrBytes
bez powodowania błędu:
db.test.aggregate(
[
{ $match: { _id: { $in: [ 2 ] } } },
{
$project:
{
_id: 0,
data: 1,
bytes: { $strLenBytes: [ "$data" ] },
result: { $substrBytes: [ "$data", 0, 5 ] }
}
}
]
)
Wynik:
{ "data" : "©♡★✪☆", "bytes" : 14, "result" : "©♡" }
Na podstawie naszego punktu początkowego 0
i nasza długość w bajtach 5
, otrzymujemy dwa znaki w naszym zestawie wyników. Dlatego widzimy, że pierwsze dwa znaki zajmują 5 bajtów.
W tym przykładzie użyłem również $strLenBytes
aby zwrócić całkowitą liczbę bajtów w ciągu. Zrobiłem to głównie po to, aby pokazać, że pięć znaków używa 14 bajtów (wiele bajtów na znak).
Oto nieco zmodyfikowany przykład, który zwraca każdy z dwóch zwróconych znaków:
db.test.aggregate(
[
{ $match: { _id: { $in: [ 2 ] } } },
{
$project:
{
_id: 0,
data: 1,
r1: { $substrBytes: [ "$data", 0, 2 ] },
r2: { $substrBytes: [ "$data", 2, 3 ] }
}
}
]
)
Wynik:
{ "data" : "©♡★✪☆", "r1" : "©", "r2" : "♡" }
Widzimy, że pierwszy znak zajmuje dwa bajty, a drugi trzy.
Niewłaściwy punkt początkowy
Jeśli punkt początkowy znajduje się w połowie znaku, wystąpi błąd.
Przykład:
db.test.aggregate(
[
{ $match: { _id: { $in: [ 2 ] } } },
{
$project:
{
_id: 0,
data: 1,
result: { $substrBytes: [ "$data", 1, 2 ] }
}
}
]
)
Wynik:
Error: command failed: { "ok" : 0, "errmsg" : "$substrBytes: Invalid range, starting index is a UTF-8 continuation byte.", "code" : 28656, "codeName" : "Location28656" } : aggregate failed : [email protected]/mongo/shell/utils.js:25:13 [email protected]/mongo/shell/assert.js:18:14 [email protected]/mongo/shell/assert.js:639:17 [email protected]/mongo/shell/assert.js:729:16 [email protected]/mongo/shell/db.js:266:5 [email protected]/mongo/shell/collection.js:1058:12 @(shell):1:1
Ten błąd mówi nam, że starting index is a UTF-8 continuation byte
. Innymi słowy, staraliśmy się zacząć w połowie postaci.
Niewłaściwy punkt końcowy
Tak samo jest z punktem końcowym. Jeśli punkt końcowy znajduje się w połowie znaku, wystąpi błąd.
Przykład:
db.test.aggregate(
[
{ $match: { _id: { $in: [ 2 ] } } },
{
$project:
{
_id: 0,
data: 1,
result: { $substrBytes: [ "$data", 0, 1 ] }
}
}
]
)
Wynik:
Error: command failed: { "ok" : 0, "errmsg" : "$substrBytes: Invalid range, ending index is in the middle of a UTF-8 character.", "code" : 28657, "codeName" : "Location28657" } : aggregate failed : [email protected]/mongo/shell/utils.js:25:13 [email protected]/mongo/shell/assert.js:18:14 [email protected]/mongo/shell/assert.js:639:17 [email protected]/mongo/shell/assert.js:729:16 [email protected]/mongo/shell/db.js:266:5 [email protected]/mongo/shell/collection.js:1058:12 @(shell):1:1
Tym razem mówi nam, że ending index is in the middle of a UTF-8 character
.