No MongoDB, o
$substrBytes
O operador de pipeline de agregação retorna a substring de uma string, com base nos índices de bytes codificados em UTF-8 especificados. Sintaxe
A sintaxe fica assim:
{ $substrBytes: [ <string expression>, <byte index>, <byte count> ] }
Onde:
<string expression>
é a corda. Pode ser qualquer expressão válida, desde que resolva para uma string.<byte index>
é onde iniciar a substring. Pode ser qualquer expressão válida, desde que resolva para um número inteiro não negativo ou número que possa ser representado como um inteiro.<byte count>
é por quantos bytes a substring deve continuar. Pode ser qualquer expressão válida, desde que resolva para um número inteiro não negativo ou número que possa ser representado como um inteiro.
Exemplo
Imagine que temos uma coleção chamada
tests
com o seguinte documento:{ "_id" : 1, "data" : "Red Firetruck" }
Podemos usar
$substrBytes
assim:db.test.aggregate(
[
{ $match: { _id: { $in: [ 1 ] } } },
{
$project:
{
_id: 0,
data: 1,
result: { $substrBytes: [ "$data", 0, 3 ] }
}
}
]
)
Resultado:
{ "data" : "Red Firetruck", "result" : "Red" }
O índice começa em zero e, portanto, nossa substring começou no início da string e continuou por três bytes.
Nesse caso, estamos usando caracteres em inglês e cada caractere é um byte. Isso facilita a contagem de quantos bytes usar.
Vamos executar outro exemplo:
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()
Resultado:
{ "data" : "Red Firetruck", "result_1" : "Fire", "result_2" : "truck", "result_3" : "truck" }
Observe que em nosso terceiro resultado, especificamos mais bytes do que estavam disponíveis, mas ele simplesmente retornou todos os caracteres ao final da string.
Caracteres de vários bytes
Alguns caracteres usam mais de um byte. Alguns usam dois, alguns usam três e alguns até usam quatro.
Aqui está um exemplo de um documento que contém vários símbolos:
{ "_id" : 2, "data" : "©♡★✪☆" }
Cada um desses caracteres usa mais de um byte. Isso significa que precisamos ter cuidado ao extrair uma substring. Precisamos ter certeza de que nosso ponto de partida não começa no meio de um personagem. Se isso acontecer, ocorrerá um erro. Da mesma forma, precisamos garantir que nosso ponto final não termine no meio de um personagem.
Por enquanto, vamos aplicar
$substrBytes
sem efetuar um erro:db.test.aggregate(
[
{ $match: { _id: { $in: [ 2 ] } } },
{
$project:
{
_id: 0,
data: 1,
bytes: { $strLenBytes: [ "$data" ] },
result: { $substrBytes: [ "$data", 0, 5 ] }
}
}
]
)
Resultado:
{ "data" : "©♡★✪☆", "bytes" : 14, "result" : "©♡" }
Com base em nosso ponto de partida de
0
e nosso comprimento de byte de 5
, obtemos dois caracteres em nosso conjunto de resultados. Portanto, podemos ver que os dois primeiros caracteres usam 5 bytes. Neste exemplo eu também usei
$strLenBytes
para retornar o número total de bytes na string. Fiz isso principalmente para mostrar que os cinco caracteres usam 14 bytes (vários bytes por caractere). Aqui está um exemplo ligeiramente modificado que retorna cada um dos dois caracteres retornados:
db.test.aggregate(
[
{ $match: { _id: { $in: [ 2 ] } } },
{
$project:
{
_id: 0,
data: 1,
r1: { $substrBytes: [ "$data", 0, 2 ] },
r2: { $substrBytes: [ "$data", 2, 3 ] }
}
}
]
)
Resultado:
{ "data" : "©♡★✪☆", "r1" : "©", "r2" : "♡" }
Podemos ver que o primeiro caractere usa dois bytes e o segundo caractere usa três.
Ponto de partida errado
Se o seu ponto de partida estiver na metade de um personagem, ocorrerá um erro.
Exemplo:
db.test.aggregate(
[
{ $match: { _id: { $in: [ 2 ] } } },
{
$project:
{
_id: 0,
data: 1,
result: { $substrBytes: [ "$data", 1, 2 ] }
}
}
]
)
Resultado:
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
Este erro nos diz que o
starting index is a UTF-8 continuation byte
. Em outras palavras, tentamos começar no meio de um personagem. Ponto final incorreto
É o mesmo com o ponto final. Se o seu ponto final estiver na metade de um caractere, ocorrerá um erro.
Exemplo:
db.test.aggregate(
[
{ $match: { _id: { $in: [ 2 ] } } },
{
$project:
{
_id: 0,
data: 1,
result: { $substrBytes: [ "$data", 0, 1 ] }
}
}
]
)
Resultado:
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
Desta vez, ele nos diz que o
ending index is in the middle of a UTF-8 character
.