firebase-admin-python icon indicating copy to clipboard operation
firebase-admin-python copied to clipboard

Python SDK and Android SDK have different start_at filtering methods

Open ETsagkaris opened this issue 5 years ago • 7 comments

I am using Firebase for a project of mine. In Android I can do a query like this:

mDatabase.child(dbRoot).child("Order").orderByChild("user_id").startAt(user.getUid(), "the order id to start from").endAt(user.getUid()).limitToFirst(15)

In "Order" object, I keep all orders made from all users. The Query gives a user's orders with pagination (it brings them in groups of 15). The problem is that in Python SDK the start_at function doesn't support the second input of starting node, and there is no way to make a similar query as far as I can tell

ETsagkaris avatar Nov 23 '20 21:11 ETsagkaris

I found a few problems with this issue:

  • I couldn't figure out how to label this issue, so I've labeled it for a human to triage. Hang tight.
  • This issue does not seem to follow the issue template. Make sure you provide all the required information.

google-oss-bot avatar Nov 23 '20 21:11 google-oss-bot

I'm not sure if the underlying REST API supports that style of queries: https://firebase.google.com/docs/database/rest/retrieve-data

@yuchenshi do you know?

hiranya911 avatar Nov 23 '20 22:11 hiranya911

Note that the given Query works exactly as explained in Android SDK, and I hope for Python SDK to make it work as also

ETsagkaris avatar Nov 23 '20 22:11 ETsagkaris

I tried to reverse engineer the code and stumbled upon the spec params that each SDK sends to decide how to filter the data. Android spec: { "vf":"l", "i":"user_id", "sn":"-MMHKiXeYhzZVSc-ryDP","ep":"OiesWhnrJqaiX7ScUoMDvpE8aSq2","l":1,"sp":"OiesWhnrJqaiX7ScUoMDvpE8aSq2"}

Python spec: {'endAt': '"OiesWhnrJqaiX7ScUoMDvpE8aSq2"', 'limitToFirst': 1, 'orderBy': '"user_id"', 'startAt': '"OiesWhnrJqaiX7ScUoMDvpE8aSq2"'}

It seems like both SDKs use the same pattern, where sp = startAt ep = endAt i = orderBy l = limitToFirst

What seems to do the trick is the "sn" parameter, which is missing in Python SDK

ETsagkaris avatar Nov 23 '20 22:11 ETsagkaris

@hiranya911 I don't work on RTDB any more, but I've got some help from @puf who figured it out:

Basically you can pass the starting node in startAt using the format "value","key", like https://stackoverflow.firebaseio.com/64961237.json?orderBy="vendor"&startAt="a","1"

In Python code, that is: params["startAt"] = valueAsJson + ',"' + key + '"'. Hope that helps.

yuchenshi avatar Nov 25 '20 21:11 yuchenshi

Yep seems to be working just fine. I monkey patched it in any case someone has the same issue as me.

def custom_start_at(self, start, key=None):
    if start is None:
        raise ValueError('Start value must not be None.')
    if key != None:
        self._params['startAt'] = json.dumps(start) + ',"' + key + '"'
    else:
        self._params['startAt'] = json.dumps(start)
    return self

db.Query.start_at = custom_start_at

ETsagkaris avatar Nov 25 '20 22:11 ETsagkaris

@ETsagkaris Would you consider opening a PR against this repository with your patch? That would help more folks in need and you may be able to remove the monkey-patch in the long run.

yuchenshi avatar Nov 26 '20 00:11 yuchenshi