Documentos de consulta de Firestore con matriz similar (Node.js/Admin SDK)

Aug 16 2020

Imagina que tienes esta matriz

[10.3, 14, 12.4, 3.5]

y en su base de datos también tiene dos documentos con esas matrices:

First document -> [10, 13.1, 0, -10]
Second document -> [0, 0, 0, 0]

Ahora imagine que tiene +1000000 documentos con las mismas dos matrices (alternando entre cada una)... ¿Hay alguna forma de obtener todos los documentos que tienen valores similares a los de su matriz actual?

Quiero decir, algo como esto:

   ...
   .where("array", "isSimilar", yourArray)
   .get()

Para obtener todos los documentos que tienen la matriz:

[10, 13.1, 0, -10]

¿O la única forma es descargar cada documento, algo que puede ser realmente lento, y luego iterar y buscar los más similares? Creo que esto puede ser muy interesante cuando se habla de "posiciones de puntos similares", "semanas en las que un usuario ha perdido peso similar",...

Gracias.

Respuestas

3 JayCodist Aug 16 2020 at 09:20

Por el momento, Firestore no admite ese tipo de consulta. Así que le sugiero que actualice su estructura para incluir un campo de cadena para la comparación de matrices. Así que cada documento se vería así:

{
   array: [12, 11, 8, 9],
   arrayStr: "12,11,8,9",
   ...
}

Puede lograr esta estructura simplemente llamando doc.array.join(",")a todos los documentos existentes y guardando el valor en el documento.

Entonces, será posible hacer las comparaciones con la consulta de firestore, así:

const arrToCompare = [12, 11, 8, 9];
const snapshot = await firestore().collection(collection).where("arrayStr", "==", arrToCompare.join(",")).get();
...

ACTUALIZACIÓN: para comparar por similitud en lugar de igualdad, un enfoque posible es aplicar su lógica de "similitud" al arrayStrcampo durante la creación. Por ejemplo, si desea que se toleren diferencias inferiores a 0,5, puede usar Math.round()en los elementos de la matriz antes de guardarlos como cadena. Al igual que:

const array = [12.2, 10.7, 8.111, 9.0];
const arrayStr = array.map(num => Math.round(num)).join(","); //"12,11,8,9"

Entonces consultarás así:

const arrToCompare = [12, 11, 8, 9];
const snapshot = await firestore().collection(collection).where("arrayStr", "==", arrToCompare.map(num => Math.round(num)).join(",")).get();
// Results would include arrays like [12.2, 10.7, 8.111, 9.0]
...

Por supuesto, podría variar el argumento pasado Math.round()para aumentar o reducir el nivel de tolerancia para las comparaciones.