neumino / thinky

JavaScript ORM for RethinkDB
http://justonepixel.com/thinky/
Other
1.12k stars 128 forks source link

Querying across n-n relationships #582

Closed curtwagner1984 closed 8 years ago

curtwagner1984 commented 8 years ago

How would one go about querying the database across relationships? Let's say we have these models with n-n relation:

var Post = thinky.createModel("Post", {
    id: type.string(),
    title: type.string(),
    content: type.string()
});
var Tag = thinky.createModel("Tag", {
    id: type.string(),
    tag: type.string()
});

Post.hasAndBelongsToMany(Tag, "tags", "id", "id")
Tag.hasAndBelongsToMany(Post, "posts", "id", "id")

How would I get all the posts that are tagged with "pizza" ? I was hoping for something like this: Post.getJoined().filter({tags: {tag:'pizza'}}).run() Sadly this doesn't seem to be tha case ...

I didn't find any solution to this in the documentation or online

simonratner commented 8 years ago

Tag.filter({tag: 'pizza'}).getJoin({posts: true}) should get you the tag with posts field populated.

neumino commented 8 years ago

What @simonratner said works.

curtwagner1984 commented 8 years ago

@simonratner Thanks! Is it possible to get an array of Post without the Tag? I've tried: Tag.filter({tag: 'pizza'}).getJoin({posts: true}).getField('posts').execute() Like suggested here #410 While this works perfectly, it returns an array of objects and not models. And if I use run() instead of execute then I get

Error: The results could not be converted to instances of Tag

@neumino In that issue you mention:

  • rewrite _model in the query to Post

Can you elaborate on what that means ?

simonratner commented 8 years ago

Tag.filter({tag: 'pizza'}).getJoin({posts: true}).then((tag) => tag.posts)?

Although to be honest, I probably wouldn't implement tags this way, instead opting for an array of tags in the post model with a corresponding multi-index. Then you can use Post.getAll(.., {index: 'tags'}).

curtwagner1984 commented 8 years ago

@simonratner So if I understand correctly I should do something like this (instead of the m-n relationship) ?


var Post = thinky.createModel("Post", {
    id: type.string(),
    title: type.string(),
    content: type.string(),
    tags: []

});
var Tag = thinky.createModel("Tag", {
    id: type.string(),
    name: type.string()
});

Post.ensureIndex("tags",{multi: true})

And then to get a post with the tag pizza: Post.getAll("pizza", {index: "tags"})

If so how will rethink know to search for pizza in the name field of a Tag ? Also is it possible to apply logic to getAll, for example, to get posts tagged with "pizza" or "spaghetti"?

simonratner commented 8 years ago

I meant using tags directly (if they are truly just tags). So what you wrote, but without the Tag model. You can query a multi-index for multiple values: Post.getAll('pizza', 'spaghetti', {index: 'tags'}). If you need something more complex than that, you can create additional indices from arbitrary functions.

Disregard if you actually need to model metadata for your tags. In that case, https://github.com/neumino/thinky/issues/582#issuecomment-257365028 is better.