Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New book not automatically added to author? #78

Open
oleersoy opened this issue Apr 18, 2017 · 12 comments
Open

New book not automatically added to author? #78

oleersoy opened this issue Apr 18, 2017 · 12 comments

Comments

@oleersoy
Copy link

Hi - I wrote this question up on stack overflow. In summary if I added a book that belongs to author 1 without also updating author 1s book IDs then I don't see that author 1 knows about the new book that it owns. Here's the full SO summary:
http://stackoverflow.com/questions/43480474/do-one-to-many-relational-pouch-instances-always-have-to-be-updated-on-both-ends

@broerse
Copy link
Collaborator

broerse commented Apr 18, 2017

You can set the dontsave option. See https://github.com/nolanlawson/ember-pouch#dont-save-hasmany-child-ids

This new mode can be selected for a hasMany relationship by specifying the option dontsave: true on the relationship.

@oleersoy
Copy link
Author

Would I do that on the schema like this:

    singular: 'author',
    plural: 'authors',
    relations: {
      books: {
        hasMany: 'book',
        dontsave: true
      }
    }

Also should it be true ... I want the books to the update on the author when I save a new book with the author specified ...?

@broerse
Copy link
Collaborator

broerse commented Apr 18, 2017

Sorry I think you are searching for this:

  {
    singular: 'author',
    plural: 'authors',
    relations: {
      books: {hasMany: {type: 'book', options: {queryInverse: 'author'}}}
    }
  },

@oleersoy
Copy link
Author

I tried it and ended up getting this:

ole@MKI:~/Junk/pouch$ rm -fr mydb/ && node index.js 
/home/ole/Junk/pouch/node_modules/relational-pouch/lib/index.js:78
          throw new Error('Invalid relationship definition for: ' + field);
          ^

Error: Invalid relationship definition for: books
    at /home/ole/Junk/pouch/node_modules/relational-pouch/lib/index.js:78:17
    at Array.forEach (native)
    at /home/ole/Junk/pouch/node_modules/relational-pouch/lib/index.js:75:35
    at Array.forEach (native)
    at PouchDB$5.exports.setSchema (/home/ole/Junk/pouch/node_modules/relational-pouch/lib/index.js:70:10)
    at Object.<anonymous> (/home/ole/Junk/pouch/index.js:5:4)
    at Module._compile (module.js:434:26)
    at Object.Module._extensions..js (module.js:452:10)
    at Module.load (module.js:355:32)
    at Function.Module._load (module.js:310:12)

This is the full script:

var PouchDB = require('pouchdb');
PouchDB.plugin(require('relational-pouch'));

var db = new PouchDB('mydb');
db.setSchema([
  {
    singular: 'author',
    plural: 'authors',
    relations: {
      books: {
        hasMany: 'book',
        options: {
          queryInverse: 'author'
        }
      }
    }
  },
  {
    singular: 'book',
    plural: 'books',
    relations: {
      author: {
        belongsTo: 'author'
      }
    }
  }
]);
db.rel.save('author', {
  name: 'George R. R. Martin',
  id: 1,
  books: [6, 7]
}).then(function() {
  return db.rel.save('book', {
    title: 'A Game of Thrones',
    id: 6,
    author: 1
  });
}).then(function() {
  return db.rel.save('book', {
    title: 'The Hedge Knight',
    id: 7,
    author: 1
  });
}).then(function() {
  return db.rel.save('book', {
    title: 'Winny the Pooh',
    id: 8,
    author: 1
  })
}).then(function() {
  var result = db.rel.find('author', 1);
  result.then(function(data) {
    console.log(data)
  });
}).catch(console.log.bind(console));

@jlami
Copy link
Collaborator

jlami commented Apr 18, 2017

@broerse did it correctly, you should make it

  {
    singular: 'author',
    plural: 'authors',
    relations: {
      books: {hasMany: {type: 'book', options: {queryInverse: 'author'}}}
    }
  },

You have the name of the type as the value of hasMany but to give options you have to give a hash to hasMany with the name in type and extra options in options. I agree it is a bit weird, but it is in line with the other options like async.

And by the way, to improve performance while doing this, make sure you setup an index on the key you are querying (+ the id field) as mentioned here: https://github.com/nolanlawson/relational-pouch#dont-save-hasmany

@oleersoy
Copy link
Author

@jlami - ah got it. I only pasted in the options object initially. However if I run the script like this:

Your Snippet

var PouchDB = require('pouchdb');
PouchDB.plugin(require('relational-pouch'));

var db = new PouchDB('mydb');
db.setSchema([
  {
    singular: 'author',
    plural: 'authors',
    relations: {
      books: {
        hasMany: {
          type: 'book',
          options: {
            queryInverse: 'author'
          }
        }
      }
    }
  }, {
    singular: 'book',
    plural: 'books',
    relations: {
      author: {
        belongsTo: 'author'
      }
    }
  }
]);
db.rel.save('author', {
  name: 'George R. R. Martin',
  id: 1,
  books: [6, 7]
}).then(function() {
  return db.rel.save('book', {
    title: 'A Game of Thrones',
    id: 6,
    author: 1
  });
}).then(function() {
  return db.rel.save('book', {
    title: 'The Hedge Knight',
    id: 7,
    author: 1
  });
}).then(function() {
  return db.rel.save('book', {
    title: 'Winny the Pooh',
    id: 8,
    author: 1
  })
}).then(function() {
  var result = db.rel.find('author', 1);
  result.then(function(data) {
    console.log(data)
  });
}).catch(console.log.bind(console));

I get this:

ole@MKI:~/Junk/pouch$ rm -fr mydb/ && node index.js 

So it does not look as if the author was added at all. Thoughts?

@jlami
Copy link
Collaborator

jlami commented Apr 18, 2017

Since you now specify that you don't want to save the hasmany side of the relationship, the line books: [6, 7] is not needed anymore, and maybe even harmful. I don't know if this is really the culprit. But it should be safe to remove, as now the reverse key author on the book type should be used.

Why the complete author document is not saved I don't really know. But maybe you can report back with the books key removed?

@oleersoy
Copy link
Author

OK I removed the books part:

db.rel.save('author', {
  name: 'George R. R. Martin',
  id: 1
}).then(function() {
  return db.rel.save('book', {
    title: 'A Game of Thrones',
    id: 6,
    author: 1
  });
}).

However the author is still not saved ...?

@jlami
Copy link
Collaborator

jlami commented Apr 19, 2017

Ok, the error is in the final step. You did not return the final promise.

}).then(function() {
  var result = db.rel.find('author', 1);
  return result.then(function(data) {
    console.log(data)
  });
}).catch(console.log.bind(console));

I inserted an extra return there. Then you will see an error. The error is due to the fact that pouchdb-find is not loaded. If you insert the following line at the top it will work correctly:
PouchDB.plugin(require('pouchdb-find'));

We will have to look into whether this should be included in the setup code of relational-pouch itself, or whether it is the job of the user. Plugin hierarchy is a bit tricky to do correctly. But for now this should fix your problem.

@oleersoy
Copy link
Author

OK Awesome!! It works now. BTW - Do you think the configuration for hasMany relationships should be made to be more symmetrical. The initial example configuration looks like this:

{singular: 'author', plural: 'authors', relations: { books: {hasMany: 'book'}}}

But if we add the inverse query option then it looks like this:

  {
    singular: 'author',
    plural: 'authors',
    relations: {
      books: { hasMany: {type: 'book', options: { queryInverse: 'author'}}}}},

So in other words it goes from { books: {hasMany: 'book'} to { books: {hasMany: {type: 'book'}

I think the type: 'book' version is also easier to read.

@fransyozef
Copy link

fransyozef commented Feb 16, 2018

Hmm I really like the "queryInverse" solution. But now I've noticed that when I look up the author and it will get the books, but in a seperate key outside "author". Is it possible to return like this:

{ author : { name :"my author", books : [ { title : "book 1" }, { title : "book 2" } ] } }

Or do I need to sort that out on my code logic side?

@jlami
Copy link
Collaborator

jlami commented Mar 1, 2018

The results are currently oriented a bit towards ember-data, which uses the JSON api internally. I guess we could give the caller extra options to configure whether to return only the ids and the objects in a seperate array as is the case now, or to return the objects embedded. But for now you should do it on your side (or you could always write a PR ;)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants