Google Cloud datastore : Use the cursor in a reverse query - google-cloud-datastore

Documentation > Datastore Queries > Limitations of cursors
sort order
An exception is if the original query's final sort order was on __key__. In that case, you can use the cursor in a reverse query, which is the original query with each sort order reversed. The reverse query can modify the start cursor, end cursor, offset, and limit.
Although it is stated that only __key__ can be used in the reverse order, it seems that it is also available in another property that created custom index. I tried it both in development environment and production environment.
What mean "An exception is if the original query's final sort order was on __key__." ?

Let me clarify this with a simple example:
Let's say you have a query (omitting cursor/limit syntax) -
SELECT * FROM MyEntity ORDER BY PROP1 ASC
Now the requirement is that you need to traverse both in forward and reverse directions and using cursors.
The first thing you need to do is to modify your query to have __key__ as the last sort -
SELECT * FROM Entity ORDER BY PROP1 ASC, __key__ ASC
You can traverse forward normally using cursors, but when you need to traverse backwards, you need to execute the query by reversing the sort order. You can still use the same cursor of the page you are on. So, the query will change to
SELECT * FROM Entity ORDER BY PROP1 DESC, __key__ DESC
Notice that we have changed ASCendng order to DESCending.
This would essentially give you the previous records from the current cursor location. In order for this to work, you need to have appropriate composite indexes (for example one on PROP1 and __key__ in DESC order). Of course you can also add other properties to the sort order, or remove PROP1 from the example, if you are fine with the results sorted just by key.
With out key as the last sort, you won't be able use the cursor you got when going forward in a reverse order query. That's what that "Exception" rule is.

Related

Cosmos db Order by on 'computed field'

I am trying to select data based on a status which is a string. What I want is that status 'draft' comes first, so I tried this:
SELECT *
FROM c
ORDER BY c.status = "draft" ? 0:1
I get an error:
Unsupported ORDER BY clause. ORDER BY item expression could not be mapped to a document path
I checked Microsoft site and I see this:
The ORDER BY clause requires that the indexing policy include an index for the fields being sorted. The Azure Cosmos DB query runtime supports sorting against a property name and not against computed properties.
Which I guess makes what I want to do impossible with queries... How could I achieve this? Using a stored procedure?
Edit:
About stored procedure: actually, I am just thinking about this, that would mean, I need to retrieve all data before ordering, that would be bad as I take max 100 value from my database... IS there any way I can do it so I don t have to retrieve all data first? Thanks
Thanks!
ORDER BY item expression could not be mapped to a document path.
Basically, we are told we can only sort with properties of document, not derived values. c.status = "draft" ? 0:1 is derived value.
My idea:
Two parts of query sql: The first one select c.* from c where c.status ='draft',second one select c.* from c where c.status <> 'draft' order by c.status. Finally, combine them.
Or you could try to use stored procedure you mentioned in your question to process the data from the result of select * from c order by c.status. Put draft data in front of others by if-else condition.

How do we apply the ORDER BY and LIMIT,OFFSET Clauses to DAO.fetch(query) in cn1-data-access?

DAO.fetch(query) allows us to get a collection of entities from the sqlite database that meets the query condition. query can be a map or string []. How can we specify ordering with the ORDER BY clause and also how do we apply the LIMIT and OFFSET clauses or do we have to default to db.execute(query)?
Currently ORDER BY, LIMIT, and OFFSET clauses aren't supported. It wouldn't be hard to add. Please file an RFE.
Alternatively it wouldn't be difficult to add this in your own DAO subclass. You can see how fetch(query) is implemented here.

In Google Datastore, is it possible to get the cursor for a specific item?

It is possible to use Datastore.key to generate a new key for an element:
const taskKey = datastore.key(['Task', 'sampleTask']);
When running a query, we may get an endCursor that can be used to get the next results.
The cursor is some base64 encoded token that contains the project ID, kind, and key of the last element fetched, with a little bit of unknown binary data.
Would there be a way/method to get that base64 cursor value given the key of an item and kind+project ID?
As previously answered, it's not possible to infer a cursor from a key because a cursor is tied to a query. You can however, filter your queries by key. E.g. select * from Task where key > Key(Task, 'sampleTask')
No, it's not possible.
Or I should rather say that it doesn't make much sense to (attempt to) obtain a cursor from an entity by itself because a cursor only has meaning in the context of the original query from which it was obtained. From Limitations of cursors (emphasis mine):
Cursors are subject to the following limitations:
A cursor can be used only by the same application that performed the original query, and only to continue the same query. To use the cursor
in a subsequent retrieval operation, you must reconstitute the
original query exactly, including the same entity kind, ancestor
filter, property filters, and sort orders. It is not possible to
retrieve results using a cursor without setting up the same query from
which it was originally generated.
Also from Cursors and data updates:
The cursor's position is defined as the location in the result list
after the last result returned. A cursor is not a relative position in
the list (it's not an offset); it's a marker to which Cloud Datastore
can jump when starting an index scan for results.

How to reverse order of SQLite CTE

If I do a simple select, I can order the result using ORDER BY. But I cannot do this with a WITH RECURSIVE CTE, because I am using it to find a path from a leaf in a tree back up to the root, and the order that the CTE creates the result is not an order that can be obtained by sorting, therefore there is no ORDER BY I can reverse to get the reverse order.
The problem I have is, this constructs the results from leaf to root, but for a subsequent part of the query I need it to be in the reverse order, from the root to the leaf. But I cannot construct the query this way because it would wind up following all branches in the tree instead of the single path that I need. Thus, I need to somehow reverse the order of the resulting CTE. How can I do this?
I have done a bit of looking and there are some similar questions for other (non SQLite) database which seem to suggest that the result of the CTE table doesn't actually have any defined order. I am not sure if that is true for SQLite - I always see it output the table in the same child to parent order, and in fact there are other cases (such as in creating temporary tables, as in a previous question I asked) where if the table were not guaranteed to have this property it would break the only possible solution rendering it an impossible problem to solve.
The documentation says:
An ORDER BY clause on the recursive-select can be used to control whether the search of a tree is depth-first or breadth-first.
However, you want to sort the ultimate output of the CTE.
This can be done easily because you are using a normal SELECT to access the CTE:
WITH RECURSIVE test1(id, parent) AS (
VALUES(3, 2)
UNION ALL
SELECT test.id, test.parent
FROM test JOIN test1 ON test1.parent = test.id)
SELECT *
FROM test1
ORDER BY id -- this sorts normally
You can use multiple elements in your order by. For example the following will order the tree by name after performing the depth first search. Here I am sorting first by LEVEL descending then NAME ascending. The output would be a sorted tree with children underneath the appropriate parent.
WITH RECURSIVE TEMPTREE (
id,
name,
level
)
AS (
SELECT flow_id,
name,
0
FROM DATATABLE
WHERE parent_id IS NULL
UNION ALL
SELECT DATATABLE.id,
DATATABLE.name,
TEMPTREE.level + 1
FROM DATATABLE
JOIN
TEMPTREE ON DATATABLE.parent_id = TEMPTREE .id
ORDER BY 3 DESC, 2 ASC
)
SELECT substr('..........', 1, level * 3) || name AS Name,
id
FROM TEMPTREE;

How to order a Doctrine Nested Set Tree when querying

I have a table that acts as a nested set.
The problem is, that the table have fields 'short_name' and 'long_name' and in different places i have to order the results accordingly.
I'm using Doctrine's "HYDRATE_RECORD_HIERARCHY" hydration mode when querying the tree.
The problem is: as far as i can tell this hydration mode is limited in terms that the query have to contain the orderBy clause "ORDER BY lft ASC"
Is there any way to get a sorted result set or do i have to apply some type of sorting after the query has been returned?
Since i'm getting back a Doctrine Collection (i'd really like to stay away from the array representation) it's not that trivial to sort it afterwards.

Resources