5
votes

So I have looked everywhere online and I just can't seem to figure out how to get this to work.

What I am trying to achieve is to find all users that have the same device under their devices. Here is the structure of the Firestore database: Database Image

So recently Firebase released version 5.3.0 of their Javascript library which in their release notes states:

Added 'array-contains' query operator for use with .where() to find documents where an array field contains a specific element.

Firebase Javascript Release Notes

I am trying to use this 'array-contains' in the .where() but i am getting no success. Here is my code: admin.firestore().collection("users").where("devices",'array-contains', id) //I get id from another place, i know that id is valid

This is the error i get back from the firebase functions log:

Unhandled error Error: Argument "opStr" is not a valid FieldComparison. Operator must be one of "<", "<=", "==", ">", or ">=". at Object.exports.(anonymous function) [as isFieldComparison] (/user_code/node_modules/firebase-admin/node_modules/@google-cloud/firestore/build/src/validate.js:89:23) at CollectionReference.where (/user_code/node_modules/firebase-admin/node_modules/@google-cloud/firestore/build/src/reference.js:1095:18) at exports.checkIfDeviceIdValid.functions.https.onCall (/user_code/index.js:23:50) at /user_code/node_modules/firebase-functions/lib/providers/https.js:330:32 at next (native) at fulfilled (/user_code/node_modules/firebase-functions/lib/providers/https.js:25:58) at process._tickDomainCallback (internal/process/next_tick.js:135:7)

Here are my dependencies from my package.json:

"dependencies": {
"@google-cloud/firestore": "^0.15.4",
"firebase-admin": "~5.13.0",
"firebase-functions": "^2.0.2"
}

If someone could help me with this and show me an example of how to do this I would greatly appreciate it. Thank you.

4
You say you want to use version 5.3.0 of the javascript library, but you're showing firebase-admin in your package.json. Are you writing frontend or backend code here? firebase-admin is for backend code only.Doug Stevenson
This is backend code @Doug StevensonAlex Rabin

4 Answers

3
votes

Version 6.0.0 - August 9, 2018 of the Firebase Admin Node.js SDK have the array-contains feature.

3
votes

Doug already hinted at the answer in his comment - the adminSDK that you are using does not yet support array-contains. The adminSDK is different than the JavaScriptSDK... which can definitely be confusing since you use JS language to utilize the adminSDK. This release-notes page does a good job demonstrating the fact that they are two separate things.

  • The JavaScript SDK is for front-end.
  • The Admin SDK is for backend (typically FB cloud functions).

Unfortunately, there's no clean way to accomplish what you're looking for on the backend. If you were doing it on the front end, you'd be able to use that handy array-contains feature the JavaScript SDK team just put out. If you have to do it on the backend, I can't think of any way other than to painfully query the whole thing and loop over the values.

There are a few alternatives to that nasty approach:

  1. If you can, move that query to the front end and take advantage of the JS-SDK's new array-contains feature.

  2. Restructure your database to avoid using the array.

  3. (not a serious option) Wait for the adminSDK team to implement this feature.

3
votes

As Doug and JeremyW have mentioned, this feature is not implemented on the adminSDK. You can restructure your database by making the devices array into a collection on the same level as the users collection. Each document in that collection will contain a device number and the id of the user. You would then be able to query the needed information:

const ids = admin.firestore().collection("devices").where("number",'==', id).select("id").get();
ids.forEach(id =>{
    admin.firestore().collection("users").doc(id)...
});

You can get more ideas from Frank van Puffelen's answer on Firebase query if child of child contains a value

0
votes

Using the following configuration, the array-contains operator works fine:

"firebase-admin": "8.0.0",
"firebase-functions": "^2.3.1",

"engines":
    "node": "8"