Documenti di query Firestore con array simile (Node.js/Admin SDK)

Aug 16 2020

Immagina di avere questo array

[10.3, 14, 12.4, 3.5]

e nel tuo DB hai anche due documenti con quegli array:

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

Ora immagina di avere +1000000 documenti con gli stessi due array (alternandoli tra loro) ... C'è un modo per ottenere tutti i documenti che hanno valori simili al tuo array attuale?

Voglio dire, qualcosa del genere:

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

In modo da ottenere tutti i documenti che hanno l'array:

[10, 13.1, 0, -10]

O l'unico modo è scaricare ogni singolo documento, cosa che può essere molto lenta, e poi iterare e cercare il più simile? Penso che questo possa essere davvero interessante quando si parla di "posizioni di punti simili", "settimane in cui un utente ha perso peso simile", ...

Grazie.

Risposte

3 JayCodist Aug 16 2020 at 09:20

Al momento, firestore non supporta questo tipo di query. Quindi ti suggerisco di aggiornare la tua struttura per includere un campo String per il confronto dell'array. Quindi ogni documento sarebbe simile a questo:

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

È possibile ottenere questa struttura semplicemente richiamando doc.array.join(",")tutti i documenti esistenti e salvando il valore nel documento.

Quindi, sarà possibile effettuare i confronti con la query firestore, in questo modo:

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

AGGIORNAMENTO: per confrontare per somiglianza anziché per uguaglianza, un possibile approccio consiste nell'applicare la logica di "somiglianza" al arrayStrcampo durante la creazione. Ad esempio, se si desidera tollerare differenze inferiori a 0,5, è possibile utilizzare Math.round()sugli elementi dell'array prima di salvare come stringa. Così:

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

Quindi interrogherai in questo modo:

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]
...

Naturalmente, potresti variare l'argomento passato Math.round()per aumentare o diminuire il livello di tolleranza per i confronti