sql >> Base de Datos >  >> NoSQL >> MongoDB

MongoDB $substrBytes

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 .