Loopback: How to access to another Model from models/ExampleModel.js ?

Created on 15 Mar 2015  Â·  26Comments  Â·  Source: strongloop/loopback

Hi,

I want to access to another model from my

module.exports = function(ExampleModel) {
//something like
//var loopback = require('loopback');
//var app = module.exports = loopback();
//var EsPlaylist = app.models.EsPlaylist;
};

Because creating remoteMethod from boot/ not working anymore with the new version.

Thanks in advance

doc

Most helpful comment

Ah hah! This took me forever to work out but I think I see the reason it wasn't working for me and probably others.

The "timing issue" @superkhau refers to above is actually very clear and easy to repair in this case. For those of us who were having trouble with finding a reference to another (unrelated) model within a model, it's simply a matter of moving the example code to where you need it (and not at the top of the model code as you would do in a classic standalone module).

So, here's the example: imagine you have this file in /common/models/example-model.js and you want to reference User within an observer (hook), for example:

Doesn't work:

module.exports = function(ExampleModel) {

var app = require('../../server/server');
var User = app.models.User;    // undefined!

ExampleModel.observe('loaded', function( ctx, next) {
   ...
   User.create(...);
   ...
});

Works:

module.exports = function(ExampleModel) {
var app = require('../../server/server');

ExampleModel.observe('loaded', function( ctx, next) {
   var User = app.models.User;    // works!
   ...
   User.create(...);
   ...
});

Also, as mentioned in the documentation and above, if you happen to have a relation between the ExampleModel and the User model (which is honestly probably what you want in this case for User specifically, though of course I agree you don't always want to have to do that), you can reference ExampleModel.app.models.User. But either way, you still need to make that reference inside one of the methods that gets called after initialization (i.e. in the same place as with the observer example above; you just don't need that kind of ridiculous relative path to the server).

If you're like me, you'll have wasted a whole night on this particular issue. I know the documentation does explain this, but not based on a "user journey", as it were. So, it takes a lot of cross-referencing, reading over and over again, looking at examples (that get complicated really quickly and thus make it hard to figure out), and frustrating trial and error, which is really not the way it should be. I just wish the documentation were better. I am sure it's being worked on, but what's there now is really painful because a lot of the details in the examples are simply wrong (either out of date, or have unforgivable typos like "user" instead of "User" in some places, and missing context in some key examples where if the examples simply showed the key boilerplate placement and didn't require the reader to go off and read a complicated and complete example codebase just to figure out one minor thing, users would be far less confused from the get-go).

Alas, whenever I see comments in threads like this that someone just suddenly got it working but can't say why, and all they know is they moved a bunch of stuff around while testing and suddenly it started working.. Not really the ideal scenario to reduce user confusion. And of course, worse yet are strange posts that go off topic and overcomplicate the issue just make it that much harder to find the right answer.

So, I sincerely hope my example above solves this particular one for the next unsuspecting frustrating user journey...

Thanks.

Steve

All 26 comments

Use ExampleModel.app.models.EsPlaylist

Not working for me.

var EsPlaylist = Playlist.app.models.EsPlaylist;
^
TypeError: Cannot read property 'models' of undefined

Are you in a boot script or in /common/models/model.js?

iam in common/models/playlist.js

module.exports = function(Playlist) {
var app = Playlist.app;
var EsPlaylist = app.models.EsPlaylist;

Did you define a relation from your model to the playlist yet? ie) ExampleModel has many EsPlaylist and EsPlayliist belongs to ExampleModel. You will need to define both sides of the relation.

Yes relations are working and i can use explorer to see the 2 models

There is no relations between this two models i just want to access to the other model from this model.

You must define the relation to access the model via the dot notation.

how can i access to others models if i don't have relation?
for exemple i want to access to User model from Example model ?
it works good when i use boot script.
I just test with putting relations it is not working.

Depends on what you're trying to do and where. See http://docs.strongloop.com/display/LB/Working+with+LoopBack+objects#WorkingwithLoopBackobjects-Gettingtheappobject

Make sure you read the entire article. What you're trying to do is already described in the "From a model script section".

Basically, if you can get a handle on the "app" object, you can access models via app.models. However, in the case of model scripts, it depends on the timing (whether the model has been registered yet).

Let me know if you need more help after.

Thanks.

it was working before just after upgrade to the last version.
If i do just like this

module.exports = function(Playlist) {
var app = Playlist.app;
console.log(app);

I have "undefined" in my console.log

I undertand it is not possible from documentation. So i have moved my code to boot script. I have another problem with Playlist.remoteMethod from boot script not add method to explorer. It works for me only when i put the remoteMethod in common/models/
Any ideas? thanks in advance

You should be defining your remote methods in /common/models/model.js. If you're a creating a remote method in there, you CAN access the app object (because its registered already at the time of invocation). Find the paragraph that says:

However, you can get a reference to the app INSIDE remote methods, remote hooks, and model hooks because those are trigger after the application finishes loading (that is, after loopback.boot runs | after /server/server.js calls boot(..)). This means you CAN do:

Also, please ask questions at our Google Group: https://groups.google.com/forum/#!forum/loopbackjs

If you want to know why: https://github.com/strongloop/loopback/wiki/Reporting-issues#question

Thanks.

Thanks for your help.

No problem. If you have any more questions, feel free to post and I will be glad to continue this conversation there. Cheers. ;)

I solved this one with the help of this thread.

I had a second object model that i did not want to create relations from, because it was a generic object and could contain variable data fields, so i simply stored the PARENT UUID in a property field of my CHILD generic object then added the dependent child UUID to an ARRAY inside a ARRAY of ANY property on the parent.

So when i accessed the parent REST stub at : /api/Restaurants/allchildren/:UUID
I would get all the objects in the CHILD object that have the UUID in that field. See my code @ :

https://gist.github.com/soltrinox/660979c359547aaefcd9

I'm pretty sure you could use this in an OPERATION HOOK to auto bind the non-related MODEL objects on a standard GET / find() request by default too. Cheers.

if you stay user model :

var app = require('../../server/server');
module.exports = function(User) {
 User.afterRemote('login', function(ctx, User, next) {
  var Role = app.models.Role;
  var Project= app.models.Project;
  ....
 });
});

Ah hah! This took me forever to work out but I think I see the reason it wasn't working for me and probably others.

The "timing issue" @superkhau refers to above is actually very clear and easy to repair in this case. For those of us who were having trouble with finding a reference to another (unrelated) model within a model, it's simply a matter of moving the example code to where you need it (and not at the top of the model code as you would do in a classic standalone module).

So, here's the example: imagine you have this file in /common/models/example-model.js and you want to reference User within an observer (hook), for example:

Doesn't work:

module.exports = function(ExampleModel) {

var app = require('../../server/server');
var User = app.models.User;    // undefined!

ExampleModel.observe('loaded', function( ctx, next) {
   ...
   User.create(...);
   ...
});

Works:

module.exports = function(ExampleModel) {
var app = require('../../server/server');

ExampleModel.observe('loaded', function( ctx, next) {
   var User = app.models.User;    // works!
   ...
   User.create(...);
   ...
});

Also, as mentioned in the documentation and above, if you happen to have a relation between the ExampleModel and the User model (which is honestly probably what you want in this case for User specifically, though of course I agree you don't always want to have to do that), you can reference ExampleModel.app.models.User. But either way, you still need to make that reference inside one of the methods that gets called after initialization (i.e. in the same place as with the observer example above; you just don't need that kind of ridiculous relative path to the server).

If you're like me, you'll have wasted a whole night on this particular issue. I know the documentation does explain this, but not based on a "user journey", as it were. So, it takes a lot of cross-referencing, reading over and over again, looking at examples (that get complicated really quickly and thus make it hard to figure out), and frustrating trial and error, which is really not the way it should be. I just wish the documentation were better. I am sure it's being worked on, but what's there now is really painful because a lot of the details in the examples are simply wrong (either out of date, or have unforgivable typos like "user" instead of "User" in some places, and missing context in some key examples where if the examples simply showed the key boilerplate placement and didn't require the reader to go off and read a complicated and complete example codebase just to figure out one minor thing, users would be far less confused from the get-go).

Alas, whenever I see comments in threads like this that someone just suddenly got it working but can't say why, and all they know is they moved a bunch of stuff around while testing and suddenly it started working.. Not really the ideal scenario to reduce user confusion. And of course, worse yet are strange posts that go off topic and overcomplicate the issue just make it that much harder to find the right answer.

So, I sincerely hope my example above solves this particular one for the next unsuspecting frustrating user journey...

Thanks.

Steve

@slgoldberg Thanks for the insight. Let's get this fixed in the docs. @crandmck ^

@slgoldberg Thanks very much for the detailed suggestion. I added this to https://docs.strongloop.com/display/LB/Working+with+LoopBack+objects#WorkingwithLoopBackobjects-Gettingareferencetoanunrelatedmodel.

Please let me know if I captured the information properly. I also added an xref in https://docs.strongloop.com/display/LB/Working+with+LoopBack+objects#WorkingwithLoopBackobjects-Fromamodelscript.

@superkhau PTAL as well.
Thanks!

Looks good, @crandmck -- thanks all for adding that. Though maybe remove the
comment "// works!" just because that was in contrast to the "doesn't work"
example in the thread and probably doesn't make sense in context with the
rest of the docs.

Thanks a lot for being so responsive to this. I think it will help greatly.
Glad to be able to help identify it.

Steve

On Fri, Jan 29, 2016 at 4:25 PM, Rand McKinney [email protected]
wrote:

@slgoldberg https://github.com/slgoldberg Thanks very much for the
detailed suggestion. I added this to
https://docs.strongloop.com/display/LB/Working+with+LoopBack+objects#WorkingwithLoopBackobjects-Gettingareferencetoanunrelatedmodel
.

Please let me know if I captured the information properly. I also added an
xref in
https://docs.strongloop.com/display/LB/Working+with+LoopBack+objects#WorkingwithLoopBackobjects-Fromamodelscript
.

@superkhau https://github.com/superkhau PTAL as well.
Thanks!

—
Reply to this email directly or view it on GitHub
https://github.com/strongloop/loopback/issues/1213#issuecomment-177030204
.

... remove the comment "// works!" ...

Done --Thanks again!

Thanks but it works only if it is not inside afterRemote

This example not work

module.exports = function(ExampleModel) {
var app = require('../../server/server');

ExampleModel.afterRemote('create', function(context, usr, next) {
ExampleModel.observe('loaded', function( ctx, next) {
   var User = app.models.User;   
   ...
   User.create(...);
   ...
}
});

i know i can get model B in model A's remote method, but this just make the code redundancy if model A have many remote methods and they all need to handle model B.
it will be nice if someone have a way to access B out of remote method, like:

module.exports = function(A) {
 var B = A.app.models.B;
};

if model is unrelated, get a reference to the main server file and get the model from it. Ex.
var app2 = require('......./server/server');
var myMod = app2.modelName;

Ref:
https://docs.strongloop.com/display/public/LB/Working+with+LoopBack+objects

I think @ChopperLee2011 has quite a genuine issue which currently I am also facing i.e It may happen that you have a large number of remotemethods on a model which may increase the size of model.js file. Is there a way we can shift the remote methods to another File and still write remote methods in it.

Was this page helpful?
0 / 5 - 0 ratings