简体   繁体   中英

Firestore Query Documents With Similar Array (Node.js/Admin SDK)

Imagine you have this array

[10.3, 14, 12.4, 3.5]

and in your DB you also have two documents with those arrays:

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

Now imagine that you have +1000000 documents with the same two arrays (alterning between each one)... Is there any way to get all documents that have similar values as your current array?

I mean, something like this:

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

So that I get all documents which have the array:

[10, 13.1, 0, -10]

Or the only way is to download every single document, something that can be really slow, and then iterate and search the most similar? I think this can be really interesting when talking about "similar points positions", "weeks in which a user has lost similar weight", ...

Thanks.

At the moment, firestore doesn't support that kind of query. So I suggest that you update your structure to include a String field for array comparison. So each document would look like this:

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

You can achieve this structure simply by calling doc.array.join(",") on all existing documents and saving the value to the document.

Then, it'll be possible to make the comparisons with firestore query, like so:

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

UPDATE: To compare by similarity instead of equality, a possible approach is to apply your "similarity" logic to the arrayStr field during creation. For example, if you want differences less than 0.5 to be tolerated, you could use Math.round() on the array elements before saving as string. Like so:

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

Then you'll query like this:

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

Of course, you could vary the argument passed to Math.round() in order to increase or reduce the level of tolerance for the comparisons

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM