GodotNuts / GodotFirebase

Implementations of Firebase for Godot using GDScript
MIT License
530 stars 76 forks source link

[BUG/FEATURE] Possibility to create subcollections, and strange behavior on how to query them? #332

Open Kontrano opened 1 year ago

Kontrano commented 1 year ago

Describe the bug As requested by KyleTheCoder an issue about the unexpected but working method.

I had a few top-level collections before, but I changed to a subcollection structure so I have {collection/document/subcollection/documents} structure.

Now when it comes to queries you would expect that you would have to feed the path into it to get to the subcollection but this doesn't work. Every subcollection with the same name seems to be joined in the backend and treated as a top-level connection which means you have to query the subcollection directly and not include any path.

To Reproduce Add subcollection To create a subcollection dynamically create a new document but instead of referencing a single collection as the collection reference feed in a path to the subcollection. as an example: {main-collection/document_id/sub-collection}

func create_document( collection : String, document_id : String, fields : Dictionary):
    var firestore_collection : FirestoreCollection = Firebase.Firestore.collection(collection)
    var add_task : FirestoreTask = firestore_collection.add(document_id, fields)
    var document : FirestoreTask = yield(add_task, "task_finished")
    return document

Query this collection by issuing a query as if it were a top-level collection, doing a path to the collection throws an error

func query(event_id):
    var query : FirestoreQuery = FirestoreQuery.new().from(" &SUBCOLLECTION_ID& ").where("event_id",FirestoreQuery.OPERATOR.EQUAL,event_id)
    var result : Array = yield(Firebase.Firestore.query(query), "result_query")
    return result`

Expected behavior I would have expected it to need a path to the collection

Environment: -Windows11

Kontrano commented 1 year ago

Update: I'm also building another app with Firebase using Flutter and Dart and in that implementation, you do need to specify the subcollection as {main-collection.document_id.sub-collection} but you can also do a compound query which is then called as {sub-collection} which combines all collection with that id. Potentially this is done by default via the Rest api?

WolfgangSenff commented 1 year ago

Okay, looking at your code, I actually think it's doing it correctly. It looks like your latter guess must be correct: it is taking the main collection ID and using it as the parent to which all subcollections are inspected with the query. I'm going to leave this open for more discussion and for anyone else to chime in, but if I'm reading the Firebase website correctly, that's how it should work for the REST API, at least.

WolfgangSenff commented 3 months ago

I'm reworking the Firestore part of the plugin and as it turns out, there's a new (or perhaps old and I missed it) way to create collections and subcollections via the REST API. I will implement it and close this when I get to it, just updating to let you know!

Kontrano commented 3 months ago

Nice thanks for the info, and as always great work on this!

theSlyest commented 1 month ago

Hello there, just to say that in my current project I am able to create sub-documents - and therefore sub-collections - and then retrieve them:

var subcollection_path: String = collection_id + "/" + document_id + "/" + subcollection_id
var subcollection : FirestoreCollection = Firebase.Firestore.collection(subcollection_path)
await subcollection.add(subdocument_id, { ... })
[...]
var subdocument = await subcollection.get_doc(subdocument_id)
WolfgangSenff commented 1 month ago

Yes, that is a known, albeit somewhat of a hack, way to do it. There's an explicit function for it that I have not yet implemented. It's fine (I personally think) to do it that way, but I'd rather implement the explicit function.

theSlyest commented 1 month ago

And queries don't work with subdocuments because of the Firebase :runQuery specification: if the collection name contains a slash "/", the HTTP request returns the following result:

[
    {
        "error": {
            "code": 400,
            "message": "Collection id \"[...]\" is invalid because it contains \"/\".",
            "status": "INVALID_ARGUMENT"
        }
    }
]
WolfgangSenff commented 1 month ago

Hm. I wonder if creating it sort of the "normal" way would fix that. I'm actually not sure - I hadn't realized that. You can definitely do a query that queries over everything in a single collection, but that's not necessarily what anyone wants, since it might be a sub-collection.