I have a table "posts" with "timestamp".
Now I want from all user that have more than 1 post, to get all posts EXCEPT the most recent post.
With this query I can successfully check the users who have more than 1 post:
r.table("post")
.group('userId')
.count()
.ungroup()
.filter(r.row("reduction").gt(1))
I can get the last post of a specific user by doing
r.table("post")
.filter({userId: 'xxx'})
.max('timestamp')
Now I need to tie those somehow together, and then compare the timestamp from each row with the max('timestamp') to see if they are not equal. The following is what I had but it's obviously wrong
.filter(r.row('timestamp').ne(r.row('timestamp').max('timestamp')('timestamp')))
Any advice how I bring all this together?
Something like this ought to work:
r.table('post')
.group({
index: 'userId'
})
.ungroup()
.filter(function(doc) {
return doc('reduction').count().gt(1)
})
.group('group')('reduction')
.nth(0)
.orderBy(
r.desc('timestamp')
).skip(1)
With reservations for syntax errors; I built this query using python and then converted it to javascript. Especially unsure about the .nth(0) part, never used it in javascript. In python it's just [0].
Related
So I'm doing some tests with GraphQL, and I'm failing in doing something that I believe is fairly simple.
When going to the GraphQL demo site (https://graphql.org/swapi-graphql) I'm presented with a default query which goes like this:
{
allFilms {
films {
title,
director,
releaseDate
}
}
}
This works as expected and returns a list of films.
Now - I would like to modify this query to return only the films where the director is George Lucas, and for the life of me - I can't figure out how to do that.
I've tried using the where and filter expressions, and also change the second line to films: (director: "George Lucas") but keep getting error messages.
What's the correct syntax for doing that?
Thanks!
If you check the docs of the provided GraphQL schema, you'll see that this is not possible. Following is the definition of the allFilms field:
allFilms(
after: String
first: Int
before: String
last: Int
): FilmsConnection
As per the doc, it has 4 input arguments, which are after, first, before, and last. There is no way to filter this out using the director's name.
GraphQL is not SQL. You cannot use expressions like WHERE or FILTER in GraphQL. The schema is already defined and the filters are pre-defined too. If the schema does not allow you to filter values using a certain field, you just can't do it.
You can to see the graphql schema here https://github.com/graphql/swapi-graphql/blob/master/schema.graphql
The allFilms query does not contain a filter for the field director. Also i can't find other query with this filter.
Most likely you need to write a filter on the result of the query.
i'm using Apollo Client do request a very structured dataset from my server. Something like
-Show
id
title
...
-Seasons
number
-Episodes
id
number
airdate
Thanks to normalization my episodes are stored individually but i cannot query them. For exemple i would like to query all the episodes to then sort them by date to display coming next.
the only way i see is to either 'reduce' my show list to an array of episode and then do the filtering. Or to do a new query to the server.
But it will be so much faster if I could get a list of all Episodes in cache.
Unfortunately with readFragment you can only query One object by its id.
Question:
Is there a way to query the cache for all object of a defined type?
The answer is late, but could have helped someone else, currently apollo does not support it. This is the issue here from github, and also a work around.
https://github.com/apollographql/apollo-client/issues/4724#issuecomment-487373566
Here is the copied workaround by #superandrew213
const serializedState = client.cache.extract()
const typeNameItems = Object.values(serializedState)
.filter(item => item.__typename === 'TypeName')
.map(item => client.readFragment({
fragmentName: 'FragmentName',
fragment: Fragment,
id: item.id,
}))
Please take note that this method is slow, especially if you have a large normalized data.
So basically how do you handle permissions?
Let's say we have a list of Post(s) of some kind, with an argument first to limit the amount of posts. And only the owner and approved users can read the posts, everyone else can't. What is the best way to implement this?
query {
{
viewer {
posts(first: 10) {
id
text
}
}
}
}
What I'm currently thinking of, is to have a single source of truth to whether a user can read the post or not, and hook it up with the dataloader module.
But, how do I query for exactly 10 posts? If I query my DB for exactly 10 rows, when I then later on filter them with some business logic, then I can get for example 8 posts returned.
A solution is to not put a limit on the query, but that's not very efficient. So what is a good way to go about this?
Inspiration from here
(1) https://dev-blog.apollodata.com/auth-in-graphql-part-2-c6441bcc4302
(2) https://dev-blog.apollodata.com/graphql-at-facebook-by-dan-schafer-38d65ef075af
(1) solved it by
export const DB = {
Lists: {
all: (user_id) => {
return sql.raw("SELECT id FROM lists WHERE owner_id is NULL or owner_id = %s, user_id);
}
}
}
as the query, and then to filter out which rows can be read:
resolve: (root, _, ctx) => {
// factor out data fetching
return DB.Lists.all(ctx.user_id)
.then( lists => {
// enforce auth on each node
return lists.map(auth.List.enforce_read_perm(ctx.user_id));
});
}
So, we can clearly see that it's querying for all the rows, even if, say, the first argument was 1, which is what I'm trying to avoid.
Maybe I'm approaching the problem wrong in some way, as the business logic lives on another layer than the DB one, so there's no way but to query all the rows. Any help appreciated.
For future reference and other people searching for solutions.
Used Dataloader to solve the authentication problem.
Literally implemented what they did in https://dev-blog.apollodata.com/graphql-at-facebook-by-dan-schafer-38d65ef075af and used this boilerplate repo as guidance. Not much more to say than that.
After looking at some SO questions and issues on RethinkDB github, I failed to come to a clear conclusion if atomic Upsert is possible?
Essentially I would like to perform the same operation as ZINCRBY using Redis.
If member does not exist in the sorted set, it is added with increment
as its score (as if its previous score was 0.0). If key does not
exist, a new sorted set with the specified member as its sole member
is created.
The current implementation appears to differ from almost all databases that I have used. With the data being replaced or inserted not updated. This is a simple use case, like update the last visit, update the number of clicks, update a product quantity. So I must be missing something very obvious, because I cannot see a simple way to do this.
Yes, it is possible. After get on the key, perform an atomic replace. Something like this might work:
function set_or_increment_score(player, points){
return r.table('scores').get(player).replace(
row =>
{ id: player,
score: r.branch(
row.eq(null),
points,
row('score').add(points))
});
}
It has the following behaviour:
> set_or_increment_score("alice", 1).run(conn)
{ inserted: 1 }
> set_or_increment_score("alice", 2).run(conn)
{ replaced: 1 }
It works because get returns null when the document doesn't exist, and a replace on a non-existing document tuns into an insert. See the documentation for replace
So I end up using the following code to go around the no Update issue.
r.db("test").table("t").insert(
{id:"A", type:"player", species:"warrior", score:0, xp:0, armor:0},
{conflict: function(id, oldDoc, newDoc) {
return newDoc.merge(oldDoc).merge(
{armor: oldDoc("armor").add(1)});
}
}
)
Do you think this is more readable/elegant or do you see any issues with the code compared to your sample?
I have a table of users who each have an array of friends.
A document in it looks something like this:
{
id: "0ab43d81-b883-424a-be56-32f9ff98f7d2",
username: "testUser1234",
friends: [
"04423c56-1890-4028-b38a-cb9aff7112de" ,
"05e4e613-2131-408c-b0ae-a952f3007405" ,
"0395ee53-8ab0-48cc-aa4e-41aad93b8737"
]
}
I want to watch for changes on a user's friends'. A query like this will get me a list of friends:
r.db("Test").table("Users").get("0ab43d81-b883-424a-be56-32f9ff98f7d2")("friends").map(function(id) {
return r.db("Test").table("Users").get(id);
})
But, when I try to throw a .changes() on the end, RethinkDB tells me that it won't work:
RqlRuntimeError: Cannot call `changes` on an eager stream in:
r.db("Test").table("Users").get("0ab43d81-b883-424a-be56-32f9ff98f7d2")("friends").map(function(var_19) { return r.db("Test").table("Users").get(var_19); }).changes()
Is there anyway to get this to work? I am afraid that my only alternative is to subscribe to the friends list (in my app) and update the subscription to the actual friends when it changes:
r.db("Test").table("Users").getAll(friendId1, friendId2 , friendId3, friendId4).changes()
Not the end of the world, but I was really excited about being able to do it entirely in the DB.
Also, can anyone explain what an "eager stream" is? I think it has something to do with lazy vs. immediate evaluation, but I had no idea how to tell what the criteria determines whether a stream is eager or not.
I can get the query working with the following formation, inspired by this post:
r.db("Test").table('Users').getAll(r.args(
r.db('Test').table('Users').get("0ab43d81-b883-424a-be56-32f9ff98f7d2")('friends')
)).changes()
You can attach the .changes before some of the transofrmations.
r.db("Test")
.table("Users")
.get("0ab43d81-b883-424a-be56-32f9ff98f7d2")
.changes()
.getField('new_val')('friends')
.map(function(id) {
return r.db("Test").table("Users").get( id );
})
Basically, every time there is a change, the map function is executed. At the moment, that is the only way to do this type of operations with .changes, but that will change in upcoming versions of RethinkDB.