Query byId() not run again for an ID even if returned fields needed are different #57

Closed
Ziink opened this Issue Dec 3, 2012 · 13 comments

Comments

Projects
None yet
5 participants

Ziink commented Dec 3, 2012

  store.query.expose 'users', 'getEmail',  (userid) ->
    @byId(userid).only(['email']);

  store.query.expose 'users', 'getName',  (userid) ->
    @byId(userid).only(['name']);

If you run the first query for a given user and then run the second query for the same user, you still get only the 'email' field. This is with 'racer-db-mongo'

lefnire commented Feb 5, 2013

This appears to be the case even if the first query is @byId but the second is a string path,. eg "users.#{userId}" with a readPathAccess accepting that path - you only get the fields limited by the original query.

This is causing me problems. I want current-user and his friends store.query.expose 'self' store.query.expose 'friends'. For self, I want the whole document - for friends, only their public fields (name, status, etc). However, subscribing to both queries restricts both to the fields returned by friends.

lefnire commented Jun 2, 2013

This is a pretty important bug, hope it's fixed in 0.5. To reword what's happening in this bug, for all motifs defined on any given collection, only one motif's returned fields part will be honored. AFAIK it's the last motif to show up in a subscription / fetch.

This means you can't have public / private things in your app. IE, you can't have public / private users (self vs friends), public / private groups, etc - you just have to have public for everything, and only display the private fields in those cases, hoping the user doesn't know about DERBY.app.model.get

see HabitRPG/habitica@8a1aae3

Contributor

SLaks commented Jun 2, 2013

AFAIK, 0.5 got rid of the ability to limit fields returned by a query, so this will no longer be relevant.

However, you may need to restructure some collections to preserve your functionality.

lefnire commented Jun 2, 2013

goodness me... seems like then we'd have to replicate users into two collections, one storing all fields, one storing private fields :/

psirenny commented Jun 2, 2013

Meh, that does seem cumbersome. Maybe they just haven't gotten around to re-implementing it yet?

Contributor

SLaks commented Jun 2, 2013

@psirenny I don't know.

@nateps, what plans do you have for fine-grained queries or access control?

Contributor

nateps commented Jun 2, 2013

@SLaks is correct. only() queries (projections in MongoDB terms) are super buggy, and they are not practical to implement in Racer 0.5. The granularity of subscriptions will only be for individual documents or queries of multiple documents.

For now, you will have to store private fields in different documents. Read access control will only allow denying access to data at the document level in the first version. However, we eventually plan to implement the ability to filter a document on a per-client basis, as long as the same client always sees the same fields from a document. If data in other parts of the document change, the client will receive notice of version updates but strip out the blocked data.

lefnire commented Jun 2, 2013

So if we used Twitter as a privacy example:

  1. self - can view / edit all fields
  2. friends - can view most fields, and send them messages (edit their messages field)
  3. public - can view basic info & tweets

Just to confirm: with 0.5, the only way to achieve this is by having 3 collections: usersPrivate, usersRestricted, usersPublic? Such that this:

model.query('users').withId(model.get('_userId')).subscribe (err, user) ->
  model.ref '_user', user

becomes this:

uid = model.get("_userId")
priv = model.query('usersPrivate').byId(uid)
res = model.query('usersRestricted').byId(uid)
pub = model.query('usersPublic').byId(uid)
model.subscribe priv, res, pub, (err, part1, part2, part3) ->
  model.ref '_user.privateFields', part1
  model.ref '_user.restrictedFields', part2
  model.ref '_user.publicFields', part3
Contributor

nateps commented Jun 2, 2013

Yeah, you'll need to do something like that for the time being. Just for the record, if you only are getting one document from a collection, its more efficient to subscribe via the path and not a query in 0.5. Example in the 0.5 api:

userId = model.get '_session.userId'
private = model.at 'usersPrivate.' + userId
restricted = model.at 'usersRestricted.' + userId
public = model.at 'usersPublic.' + userId
model.subscribe private, restricted, public, (err) ->
  model.ref '_page.user.private', private
  model.ref '_page.user.restricted', restricted
  model.ref '_page.user.public', public
Contributor

nateps commented Jun 4, 2013

No longer relevant in 0.5

@nateps nateps closed this Jun 4, 2013

@lefnire lefnire referenced this issue in HabitRPG/habitica Jun 4, 2013

Closed

Habits and Tasks have disappeared! #1133

lefnire commented Jun 9, 2013

However, we eventually plan to implement the ability to filter a document on a per-client basis, as long as the same client always sees the same fields from a document.

Strikes me that this will effectively be the same thing as projections, unless I'm misunderstanding?

Contributor

nateps commented Jun 9, 2013

The difference is that projections mean you can create queries for different parts of your application that return different subsets of the same document. This is difficult to manage in ShareJS / Racer, since a client only has one snapshot of a document. If you were to do two different queries on the same document with different projections, we would somehow have to merge multiple projections of the same snapshot together. Since the different snapshots could be at different versions, this is not practical. We have no plans to implement this feature anytime soon, since you can simply structure your documents such that the amount of data returned is reasonable.

The access control filters will be different, because a client will only be able to subscribe to the exact same fields from a document. Thus, we don't have to worry about maintaining separate projections and merging them together. All we'll do is filter out the same properties every time we send a document or operation within a document to that client. If all fields in the update are filtered out, the client will still get notice of a version increase but not get the data. Note that we aren't implementing the access filter just yet, and access control has to be at the document level for now.

lefnire commented Jun 9, 2013

I see, that makes sense now. Very informative, thanks Nate!

lefnire added a commit to HabitRPG/habitica that referenced this issue Nov 11, 2013

groups: very precarious placement of query motifs and subscription /
fetch order due to derbyjs/racer#57 for
guilds, party, habitRPG group, and publicGroups.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment