Grapher - Collection Relationship Manager + GraphQL Like Data Fetcher

Thanks for the response @diaconutheodor!

I guess, it’s about time to upgrade. I will definitely test grapher and redis oplog! :wink:

1 Like

Yo yo yo! 1.2.5 is out!

What’s new:

Sync fetching to support Redux Sagas or anything you wish! :slight_smile: I personally don’t use Redux unless I have some complex mgmt to do, but ofcourse there are many other uses for this.

  • Auto-remove now works from inversed-side as well.

What’s next ?
I personally think that Grapher should remain dumb. Some people have suggested implementing machine learning algorithms, complex conditional searches. However I am not sure whether or not this is the right path to go. Complex conditional searches can be achieved with some boilerplate and namedQueries. My thoughts are that if I could find a way to allow the use of aggregate framework inside grapher, a lot of problems can be solved. I am uncertain.

Happy coding!

5 Likes

1.2.6 is out

After having over 5 projects in production with this, and other friends and people using it, we found some very nice edge-cases and we solved them. Currently Grapher is in a feature-lockdown. Meaning we work on making as perfect as possible. It is already production ready for over 3 months, and a lot of people are happily using it.

Cheers.

4 Likes

I’m having a bit of a problem here. I want to add my users to groups (without using alanning:roles). I’ve defined the links thus:

(<any>Gruppen).addLinks({
    usersInGruppe: {
        type: 'many',
        collection: Users,
        field: 'userIds'
    }
});

(<any>Users).addLinks({
    userGruppe: {
        collection: Gruppen,
        inversedBy: 'usersInGruppe'
    }
})

I have a query which works:

const query = createNamedQuery('alleUser', {
    users: {
        _id: 1,
        username: 1,
        emails: 1,
        profile: 1,
        userGruppe: {
            content: 1
        }
    }
});

and I’m getting the link like this:

let link = (<any>Users).getLink(value, 'userGruppe');
link.set(gruppenId);

The subscriptions are working as well, and just for testing purposes, the Gruppe is wide-open for development, allowing updates, deletions and insertions.

Now, here is the main issue:

After setting the relationship I can see that the user object does contain the value for the collection gruppe once. After that, it’s updated and the reference becomes empty once again. However, I can see the change in MongoDB.

The same code also works for a one-to-one relationship.

So, obviously, while the change is accepted on the client something on the server-side disagrees. I don’t get an error anywhere, though, which makes it hard to track down.

And another thing: I was under the impression that link.set() was for one-to-relationships while link.add() was for many-to-relationships.

However, it seems that you can define only one-to-one or many-to-many. One-to-many is kind of hard to establish. If I’m calling link.set() from the inversed side of a link, it simply behaves like link.add() instead of unsetting the old link before setting a new one, forcing me to clean up the related arrays manually.

Figured it out. This should really go into the documentation at a very prominent place:

See that field userIds up there where I defined the links? You need to include that field in your query.

Read here: http://grapher.cultofcoders.com/api/links.html#Managing-Links-Inversed and the reasoning behind this choice.

See that field userIds up there where I defined the links? You need to include that field in your query.

I don’t understand this. Show me an example of what you would add to the docs to clarify this issue, I’m still a bit confused.

Here’s the query for the groups in its original form:

export const gruppenQuery = (<any>Gruppen).createQuery({
    content: 1,
    usersInGruppe: {
        username: 1
    }
})

This will always yield an empty result, for both the user and the group collection. It will work if I change it to this:

export const gruppenQuery = (<any>Gruppen).createQuery({
    content: 1,
    userIds: 1,
    usersInGruppe: {
        username: 1
    }
})

Then what you have is a bug, you don’t have to specify the relation storage field to be able to get the users. A reproduction repo would be more than helpful. And make sure you’re on latest version.

Also, are you working with a reactive query or non-reactive ?

Reactive. And I am on the latest version.

@rhywden did you manage to solve the problem ? What you are facing is also present in the test, and they pass. Can I be of any assistance to you ?

Didn’t have time to properly search for the issue, sorry. Will see if I can create a reproduction this weekend.

Hi @diaconutheodor ,

This package looks great, it solves many of the pain points of using Meteor + Mongo. I was looking at the documentation and I was wondering if it is possible to use this with React Native.

Thanks in advance.

1 Like

@indesign it uses methods and pub/sub for reactive data graphs. so I would say yes. It works.

Hello @diaconutheodor

Thanks for the amazing package. I was wondering if there is a way in this package to establish links using dot notation or some other format to access data not on the top level of the Mongo document.

For instance:

Collection.addLinks({
	user: {
		          collection: Users,
		          type:       'one',
		          field:      'relationalIds.userId',
		          index:      true
	          }
})


@diaconutheodor, Very interested in using “group by” aggregation with Grapher. We currently can use Grapher to create “fact” tables, then use MongoDb aggregation, but would love to be able to use group by aggregation directly in Grapher so we don’t have to maintain fact tables with ETL, etc, just to do group by aggregation. How are other people handling aggregation reporting with big MongoDB based production apps?

@diaconutheodor is Grapher compatible with SimpleSchema 2.0 on NPM?

Aldeed is transitioning Simple Schema:
https://github.com/aldeed/meteor-simple-schema/blob/v2/CHANGELOG.md#200
and

Hi, currently there’s no tested way of doing that. I’d recommend keeping relations topLevel. It’s just better for consistency.

I see your point. It’s something I should rethink, the idea is here is if you want performance, we use the hypernova module for aggregation and assembly, the problem is that if you want to use aggregate, we would have to somehow tune-in into that system, and not affect it’s output because assembly process would fail.

So. Grapher shines in fetching related data in mongodb at lightning speeds, so if you have a complex aggregate, write it out-side it, it’s not meant for that.

Keep in mind you can always write a “Resolver Link”, which does the aggregation for you, and you could use it as a field in your query :slight_smile:

We will need to add a handler for it to make it work with both, depending on the attached schema on your collection. Good point.

Hi,

I’m intrested in switching to graphQL or grapher. I’m also intrested, but by no means expert, in using graphs to traverse data. I’ve been reading about graphs and like the idea proposed by Neo4j for example of treating relationships as first class citizens. I understand that to be related to the ability to add attributes directly to the relationships (links). So my question is, do these query languages (graphql or graphql like (ala grapher)) bring me any closer the that idea. In grapher can I add attributes directly to links (possibly they would be normailized to mongdb in some way)? I see metadata but it doesn’t seem to be the same.

I hope the question makes sense. Thanks.

I still hadn’t time to create a repro for the bug I mentioned, sorry. In the meantime, maybe you or someone else could help me with this feature I’d like to implement? I’m not quite sure how best to approach it in terms of exposure / firewall.

I also don’t want to use alanning:roles because the collections I am now detailing get more metadata.

Basically, I have some pupils (i.e. the user collection). The pupils are then divided into groups (as in: Exam_in_2017, Exam_in_2018, Exam_in_2019). And each group then gets several courses (Physics_2017-2018, Chemistry_2016-2017). Each course then has, for example, specific coursework (or tasks. or transcripts)

So, exemplary, Pupil_A is in Exam_in_2018 and thus member of Physics_2016-2017 and Physics_2017_18.

I’m creating those links with the usual tools, that part is working.

Now, here’s my question: How do I make sure that Pupil_A gets only the coursework (or whatever) for the two courses he’s member of?

@rhywden

Now, here’s my question: How do I make sure that Pupil_A gets only the coursework (or whatever) for the two courses he’s member of?

You can use your groups as an intermediary for the courses.

users: {
   $filters: { _id: userId },
   groups: {
       courses: { name: 1 }
   }
}
courses = _.union(_.pluck(users.groups, 'courses'))
1 Like