-
-
Notifications
You must be signed in to change notification settings - Fork 3.8k
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
Temporary (virtual) properties on model instance #2642
Comments
Virtuals are the correct way to do this. The method you described with |
Well I didn't try |
I don't quite understand the last question. Can you please elaborate? |
It seems set/get doesn't work for me. One more time: I want to ``set/get` property that is NOT defined on schema. Its is only temporary. The property should be processed with toObject, toJSON, but should not be saved to DB. So it is like virtual or terporary. Look at my code example in OP. |
Both of the below options work for what you're trying to do as far as I can tell: var Schema = mongoose.Schema;
mongoose.connect('mongodb://localhost:27017/gh2642');
var parentSchema = new Schema({ name: String });
var Parent = mongoose.model('gh2642', parentSchema, 'gh2642');
var p = new Parent({ name: 'test' });
p.children = { a: 1 };
console.log(JSON.stringify(p.children));
p.save(function(err, p) {
}); and var Schema = mongoose.Schema;
mongoose.connect('mongodb://localhost:27017/gh2642');
var parentSchema = new Schema({ name: String });
parentSchema.virtual('children').
get(function() {
return this.__children;
}).
set(function(v) {
this.__children = v;
});
var Parent = mongoose.model('gh2642', parentSchema, 'gh2642');
var p = new Parent({ name: 'test' });
p.children = { a: 1 };
console.log(JSON.stringify(p.children));
p.save(function(err, p) {
}); In both cases |
Your first code example (where you do not define virtual property That is what about I'm talking. It only works if you have a definition for virutual property like this: parentSchema.virtual('children').
get(function() {
return this.__children;
}).
set(function(v) {
this.__children = v;
}); The issue was about gettring rid of this exessive code. |
Again about this issue I do not think it is resolved. yes this code
works in 3.9 (though it seemd not to work in 3.8 parentSchema.virtual('children').
get(function() {
return this.__children;
}).
set(function(v) {
this.__children = v;
}); So why not allow this with just one line, that would make all the stuff internaly parentSchema.virtual('children') ? |
Too much magic under the hood IMO - what if you have a schema path called It would be pretty easy to implement this with a plugin though, if it really bugs you. |
yes I undertand it, |
The general idea is good, but I think its tricky to get it right in the general case. Avoiding schema paths, etc. will make this more trouble than it's worth to trim 6 SLOC. |
Does virtual solves this problem? |
only using such hack: parentSchema.virtual('children').
get(function() {
return this.__children;
}).
set(function(v) {
this.__children = v;
}); |
@vkarpov15, is it safe to use More specifically, do documents (or their prototypes) have any internal/non-enumerable properties that start with |
Is it possible to pass nodejs/express request req inside virtual property?
|
@vko Sure it's possible, but probably not the best idea as you would need to use some scoping magic and define your schema within a particular express route handler or param middleware... You're asking a specific question that is more relevant to function scoping than mongoose virtuals... http://ryanmorr.com/understanding-scope-and-context-in-javascript/ |
@techjeffharris is there any demo? I really want this but not sure how it's done. |
@techjeffharris I think it should be safe @vko-online not really possible, I would advise against trying to do that. |
@vkarpov15 sounds like it will work for now. Thank you! I'll investigate what it would take to add a schema method called |
@techjeffharris you can use |
@whitecolor Haha |
Just make sure you don't use |
I found a alternate way to solve the problem. As its JavaScript adding property on the go is not a problem. The problem is here with the toJson or toObject. you can overcome that bu over riding those methods. This is better over mongoose transform. I believe wont work in the scenario when you delete the backing field the virtual will lose the source of information. therefore will not show-up in JSON. |
Hey, for thouse who intrested you can check my current implementation for virtual async fields api. https://github.com/whitecolor/mongoose-fill I think mongoose.js actually should have something like this in the core. Intresting in you oppinion. |
@whitecolor sweet module! Way to go, I really like the plugin's API and I'm looking forward to using it. But looks like it isn't up on npm yet? https://www.npmjs.com/package/mongoose-fill |
@whitecolor this __fill.fill.fill looks really weird, just sayin |
@vkarpov15 published it. @vko-online its in dev mode so convetions and terms in the code may seem not clear. __fill - is actually is object that contains info about what should be filled in particular query We use it in our projects and we like api that it provides and allows to fill/combine mongoose objects with any kind of data, not only form current mongoose DB, but also from any async service. |
@whitecolor perhaps my usage of virtual properties is deferent a bit unorthodox compared to yours, but this module seems IMHO a bit of a complicated workaround to simply not store an array of child IDs. If the parent had an array of refs to the child IDs, one could simply populate the array of children and only select the name and age properties. I'm using virtual properties to attach data (for instance, socket.io "sockets" for a user—each page refresh end and creates a new socket) which is expires when the process closes (or sooner) and is thus worthless to store in the db, but is nonetheless useful to have associated with a user model. I'm writing a glorified chat server that caches all users from db at startup, then adds references to each of the users sockets (open windows with the same user session) to the document instance. If he serve restarts or closes, the sockets close and new sockets are made when the sever is back up and each window reconnects. I suppose it's a more SQL-like way of doing things, stirring the parent ID in the child rather than storing child IDs in the parent, but I feel like using refs and populating the parent is effectively the same. Though, admittedly, I may be missing something. I'm glad that you made something that works for you, nonetheless 😄 |
@techjeffharris But often such solid connections are really exessive and add additional potential breaking point that you really want to avoid. In my oppinion if you can avoid exessive linking (coupling) in you architecture - you shoud (or must) avoid it. Yes it is some kind of SQL normalized structure way, but it simplifies things by reducing coupling and makes design more flexible. |
@techjeffharris Storing the parentSchema.virtual('children', {
ref: 'Child',
localField: '_id',
foreignField: 'parentId',
}); Then when you want the children for any given parent you would simply do: Parent.findOne({..}).populate('children').exec(function(err, parent) {
if (err) {
next(err);
} else {
res.send(parent.toObject({virtuals: true});
}
});
// or using promise syntax
Parent.findOne({...}).populate('children').exec()
.then((parent) => res.send(parent.toObject({virtuals: true}))
.catch(next) Also note that you can omit the |
Sometimes I need to have on a model instance some temporaty property that is not in DB but for example I want to send to the client.
The scenario:
say I a have a
Parent
Model andChild
model, I store them in separeate collections and onlyChild
model has reference to it's parentthe problem is that
parent.children = children
won't work ifchildren
property is not defined onParent
schema. But its only temporary property and should not be saved to DB, it is not reasonable (and just incorrect) to define it onParent
schema.The workaround I found is to add the followin virtual peroperty to
Parent
model:I thought maybe something like that could work for such proerties:
What do you think?
The text was updated successfully, but these errors were encountered: