mobizt/Firebase-ESP-Client

Firestore

DiSkyMaster opened this issue · 11 comments

I'm sorry if I didn't follow the format or if I opened an issue incorrectly.

I just have a problem and I'm not sure how to do it. My firebase firestore database information is as in the image below. I login with nodemcu by entering my email and password. But I only know X220 without knowing the user's uid. X220 is unique information.
Only one user can have one. So when I know that, I can only know that it belongs to that user. Anyway, my goal is to edit the blue, red, white information of the X220 (it doesn't matter which user it belongs to). For example like here whereEqualTo("devices", "X220")

In summary, I want to get and edit the blue, red, white information of a unique device ID named X220, which has hundreds of users and only one device out of dozens of devices.

image
image

mobizt commented

You should read the Firestore REST API documentation for what features that API provided.

For your required feature, please try this example first to see how you can filter with runQuery function.

Then you should compose your query with StructuredQuery from this document.
https://cloud.google.com/firestore/docs/reference/rest/v1/StructuredQuery

From the doc, you will see the where query that can be composed from one of the filters i.e., compositeFilter, fieldFilter and unaryFilter.

The FieldFilter will match your requirement with EQUAL operator.

I'm never try with this feature in dept and I'm quite sure that this matches your requirement.

I'm not sure of its accuracy. I tried several times but couldn't get the result I wanted. How should I go about this?

In my last few attempts and in the code above I also get the following error:

  • Invalid JSON payload received. Unknown name "structuredQuery" at 'document': Cannot find field.
    FirebaseJson query;
    query.set("where/fieldFilter/field/fieldPath", "devices");
    query.set("where/fieldFilter/op", "EQUAL");
    query.set("where/fieldFilter/value/stringValue", "X220");
    query.set("limit", 1);
    
    if (Firebase.Firestore.runQuery(&fbdo, FIREBASE_PROJECT_ID, "", "users", &query))
      Serial.printf("ok\n%s\n\n", fbdo.payload().c_str());
    else
      Serial.println(fbdo.errorReason());```
mobizt commented

The Firestore 's StructuredQuery is similar to SQL language used in rational database.

Your StructuredQuery is missing "select" and "from" queries.

Thank you for your return. I made a few more attempts. I'm still getting the same error. The last example I tried:

    query.set("select/fields/[0]/fieldPath", "red");
    query.set("select/fields/[1]/fieldPath", "blue");
    query.set("select/fields/[2]/fieldPath", "white");
    
    query.set("from/collectionId", "devices");
    query.set("from/allDescendants", false);

    query.set("where/fieldFilter/field/fieldPath", "devices");
    query.set("where/fieldFilter/op", "EQUAL");
    query.set("where/fieldFilter/value/stringValue", "X220");

    query.set("limit", 1);
mobizt commented

The document path "users" is not valid. It should be full path of document that contains the collection "devices".

In your case, the valid document path is.
"users/EaHGDj4eI3dgr3eoiP3PH7yIPm12"

This is not valid.
query.set("where/fieldFilter/field/fieldPath", "devices");

Which "devices" is collection id not a field.

Please see the data model doc.

I don't think that data query was designed for document id filtering, instead of data (field) filtering.

In your case, I recommend you storing your document name as a field in that document too and query from that field.

For example, if the field "user_id" used to store its document id like the following.

Field "user_id" in document "user1" store value "user1".
Field "user_id" in document "user2" store value "user2".
Field "user_id" in document "X220" store value "X220".

Then you can use.

query.set("where/fieldFilter/field/fieldPath", "user_id");

Thanks for your return. I think I'm on the right track. I have now added an id field next to the blue, red, white fields. I set this id as X220. And my code is now like this:

    FirebaseJson query;
    
    query.set("select/fields/[0]/fieldPath", "red");
    query.set("select/fields/[1]/fieldPath", "blue");
    query.set("select/fields/[2]/fieldPath", "white");
    
    query.set("from/collectionId", "devices");
    query.set("from/allDescendants", false);

    query.set("where/fieldFilter/field/fieldPath", "id");
    query.set("where/fieldFilter/op", "EQUAL");
    query.set("where/fieldFilter/value/stringValue", "X220");

    query.set("limit", 1);
    
    if (Firebase.Firestore.runQuery(&fbdo, FIREBASE_PROJECT_ID, "", "devices/X220", &query))
      Serial.printf("ok\n%s\n\n", fbdo.payload().c_str());
    else
      Serial.println(fbdo.errorReason());

When I use it this way it gives me the ok return and the following output. But I still can't get the blue, red, white field.

[
	{
		"readTime":"2023-07-29T09:35:39.286903Z"
	}
]
mobizt commented

You should read my previous post carefully.

The document at the path "devices/X220" you provided in Firebase.Firestore.runQuery does not contains the collection "devices".

I already show your correct document path and it should be absolute path from root.

The ESP needs to do this without knowing "EaHGDj4eI3dgr3eoiP3PH7yIPm12". The device with the id of X220 will not know which user uid it has. This X220 can only be in one user. For example, let it be the user with the uid "EaHGDj4eI3dgr3eoiP3PH7yIPm12". ESP, on the other hand, will attract the user who owns this X220 with runQuery and reach the devices it owns and the fields of the devices. This is my aim.

That's why I can't write "users/EaHGDj4eI3dgr3eoiP3PH7yIPm12" in path. How can I do this differently without knowing the "EaHGDj4eI3dgr3eoiP3PH7yIPm12" information? How should I set this up?

mobizt commented

It's not possible to do what you need.

This is Firestore not Firebase RTDB database which they have different data model.

You should keep in mind what is Firestore data model which it stated clearly in the Firestore documentation.

mobizt commented

You should avoid leaving blank document name when creating/committing the document because it will create document with random UID as you get which unpredictable for further access.

mobizt commented

You should ask this such question on the community forum or contact google support team.