In MongoDB, il $substrBytes
l'operatore della pipeline di aggregazione restituisce la sottostringa di una stringa, in base agli indici di byte codificati UTF-8 specificati.
Sintassi
La sintassi è questa:
{ $substrBytes: [ <string expression>, <byte index>, <byte count> ] }
Dove:
<string expression>
è la stringa. Può essere qualsiasi espressione valida purché si risolva in una stringa.<byte index>
è dove iniziare la sottostringa. Può essere qualsiasi espressione valida purché si risolva in un numero intero non negativo che può essere rappresentato come un intero.<byte count>
è per quanti byte deve continuare la sottostringa. Può essere qualsiasi espressione valida purché si risolva in un numero intero non negativo che può essere rappresentato come un intero.
Esempio
Immagina di avere una raccolta chiamata tests
con il seguente documento:
{ "_id" : 1, "data" : "Red Firetruck" }
Possiamo usare $substrBytes
così:
db.test.aggregate(
[
{ $match: { _id: { $in: [ 1 ] } } },
{
$project:
{
_id: 0,
data: 1,
result: { $substrBytes: [ "$data", 0, 3 ] }
}
}
]
)
Risultato:
{ "data" : "Red Firetruck", "result" : "Red" }
L'indice inizia da zero, quindi la nostra sottostringa è iniziata all'inizio della stringa e ha continuato per tre byte.
In questo caso, utilizziamo caratteri inglesi e ogni carattere è un byte. Questo ci rende facile contare quanti byte usare.
Facciamo un altro esempio:
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()
Risultato:
{ "data" : "Red Firetruck", "result_1" : "Fire", "result_2" : "truck", "result_3" : "truck" }
Nota nel nostro terzo risultato, abbiamo specificato più byte di quelli disponibili, ma ha semplicemente restituito tutti i caratteri alla fine della stringa.
Caratteri multibyte
Alcuni caratteri utilizzano più di un byte. Alcuni ne usano due, altri tre e altri addirittura quattro.
Ecco un esempio di documento che contiene una serie di simboli:
{ "_id" : 2, "data" : "©♡★✪☆" }
Ciascuno di questi caratteri utilizza più di un byte. Ciò significa che dobbiamo fare attenzione quando si estrae una sottostringa. Dobbiamo essere sicuri che il nostro punto di partenza non inizi a metà di un personaggio. In tal caso, si verificherà un errore. Allo stesso modo, dobbiamo assicurarci che il nostro punto finale non finisca a metà di un personaggio.
Per ora, applichiamo $substrBytes
senza effettuare un errore:
db.test.aggregate(
[
{ $match: { _id: { $in: [ 2 ] } } },
{
$project:
{
_id: 0,
data: 1,
bytes: { $strLenBytes: [ "$data" ] },
result: { $substrBytes: [ "$data", 0, 5 ] }
}
}
]
)
Risultato:
{ "data" : "©♡★✪☆", "bytes" : 14, "result" : "©♡" }
Basato sul nostro punto di partenza di 0
e la nostra lunghezza in byte di 5
, otteniamo due caratteri nel nostro set di risultati. Quindi possiamo vedere che i primi due caratteri usano 5 byte.
In questo esempio ho usato anche $strLenBytes
per restituire il numero totale di byte nella stringa. L'ho fatto principalmente per mostrare che i cinque caratteri utilizzano 14 byte (più byte per carattere).
Ecco un esempio leggermente modificato che restituisce ciascuno dei due caratteri restituiti:
db.test.aggregate(
[
{ $match: { _id: { $in: [ 2 ] } } },
{
$project:
{
_id: 0,
data: 1,
r1: { $substrBytes: [ "$data", 0, 2 ] },
r2: { $substrBytes: [ "$data", 2, 3 ] }
}
}
]
)
Risultato:
{ "data" : "©♡★✪☆", "r1" : "©", "r2" : "♡" }
Possiamo vedere che il primo carattere usa due byte e il secondo carattere ne usa tre.
Punto di partenza sbagliato
Se il tuo punto di partenza è a metà di un carattere, si verifica un errore.
Esempio:
db.test.aggregate(
[
{ $match: { _id: { $in: [ 2 ] } } },
{
$project:
{
_id: 0,
data: 1,
result: { $substrBytes: [ "$data", 1, 2 ] }
}
}
]
)
Risultato:
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
Questo errore ci dice che l'starting index is a UTF-8 continuation byte
. In altre parole, abbiamo cercato di iniziare a metà di un personaggio.
Punto finale sbagliato
È lo stesso con il punto finale. Se il tuo punto finale è a metà di un personaggio, si verifica un errore.
Esempio:
db.test.aggregate(
[
{ $match: { _id: { $in: [ 2 ] } } },
{
$project:
{
_id: 0,
data: 1,
result: { $substrBytes: [ "$data", 0, 1 ] }
}
}
]
)
Risultato:
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
Questa volta ci dice che l'ending index is in the middle of a UTF-8 character
.