En MongoDB, el $substrBytes
El operador de canalización de agregación devuelve la subcadena de una cadena, en función de los índices de bytes codificados en UTF-8 especificados.
Sintaxis
La sintaxis es así:
{ $substrBytes: [ <string expression>, <byte index>, <byte count> ] }
donde:
<string expression>
es la cadena. Puede ser cualquier expresión válida siempre que se resuelva en una cadena.<byte index>
es donde comenzar la subcadena. Puede ser cualquier expresión válida siempre que se resuelva en un número entero no negativo o un número que se pueda representar como un número entero.<byte count>
es por cuántos bytes debe continuar la subcadena. Puede ser cualquier expresión válida siempre que se resuelva en un número entero no negativo o un número que se pueda representar como un número entero.
Ejemplo
Imagina que tenemos una colección llamada tests
con el siguiente documento:
{ "_id" : 1, "data" : "Red Firetruck" }
Podemos usar $substrBytes
así:
db.test.aggregate(
[
{ $match: { _id: { $in: [ 1 ] } } },
{
$project:
{
_id: 0,
data: 1,
result: { $substrBytes: [ "$data", 0, 3 ] }
}
}
]
)
Resultado:
{ "data" : "Red Firetruck", "result" : "Red" }
El índice comienza en cero, por lo que nuestra subcadena comenzó al comienzo de la cadena y continuó durante tres bytes.
En este caso, estamos usando caracteres ingleses y cada carácter es un byte. Esto nos facilita contar cuántos bytes usar.
Ejecutemos otro ejemplo:
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 en nuestro tercer resultado que especificamos más bytes de los que estaban disponibles, pero simplemente devolvió todos los caracteres al final de la cadena.
Caracteres de varios bytes
Algunos caracteres usan más de un byte. Algunos usan dos, algunos usan tres y algunos incluso usan cuatro.
Aquí hay un ejemplo de un documento que contiene un montón de símbolos:
{ "_id" : 2, "data" : "©♡★✪☆" }
Cada uno de estos caracteres utiliza más de un byte. Esto significa que debemos tener cuidado al extraer una subcadena. Necesitamos estar seguros de que nuestro punto de partida no comienza a la mitad de un personaje. Si lo hace, se producirá un error. Del mismo modo, debemos asegurarnos de que nuestro punto final no termine a la mitad de un personaje.
Por ahora, apliquemos $substrBytes
sin efectuar un error:
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" : "©♡" }
Basado en nuestro punto de partida de 0
y nuestra longitud de bytes de 5
, obtenemos dos caracteres en nuestro conjunto de resultados. Por lo tanto podemos ver que los primeros dos caracteres usan 5 bytes.
En este ejemplo también usé $strLenBytes
para devolver el número total de bytes en la cadena. Hice esto principalmente para mostrar que los cinco caracteres usan 14 bytes (múltiples bytes por carácter).
Aquí hay un ejemplo ligeramente modificado que devuelve cada uno de los dos caracteres devueltos:
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 el primer carácter usa dos bytes y el segundo carácter usa tres.
Punto de partida incorrecto
Si su punto de partida está a la mitad de un carácter, se produce un error.
Ejemplo:
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 error nos dice que el starting index is a UTF-8 continuation byte
. En otras palabras, intentamos comenzar a la mitad de un personaje.
Punto final incorrecto
Es lo mismo con el punto final. Si su punto final está a la mitad de un carácter, se produce un error.
Ejemplo:
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
Esta vez nos dice que el ending index is in the middle of a UTF-8 character
.