Mongodb findOne - return value [duplicate]
This question already has an answer here:
How do I return the response from an asynchronous call?
33 answers
I need to fetch id of user from collection 'users' by calling a function and return it's value.
fetchId = (name) => {
User.findOne({name: name}, (err, user) => {
return user._id;
});
};
But this implementation returns null. What is the way to fix it?
javascript node.js mongodb
marked as duplicate by JohnnyHK
StackExchange.ready(function() {
if (StackExchange.options.isMobile) return;
$('.dupe-hammer-message-hover:not(.hover-bound)').each(function() {
var $hover = $(this).addClass('hover-bound'),
$msg = $hover.siblings('.dupe-hammer-message');
$hover.hover(
function() {
$hover.showInfoMessage('', {
messageElement: $msg.clone().show(),
transient: false,
position: { my: 'bottom left', at: 'top center', offsetTop: -7 },
dismissable: false,
relativeToBody: true
});
},
function() {
StackExchange.helpers.removeMessages();
}
);
});
});
Nov 15 '18 at 16:38
This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.
add a comment |
This question already has an answer here:
How do I return the response from an asynchronous call?
33 answers
I need to fetch id of user from collection 'users' by calling a function and return it's value.
fetchId = (name) => {
User.findOne({name: name}, (err, user) => {
return user._id;
});
};
But this implementation returns null. What is the way to fix it?
javascript node.js mongodb
marked as duplicate by JohnnyHK
StackExchange.ready(function() {
if (StackExchange.options.isMobile) return;
$('.dupe-hammer-message-hover:not(.hover-bound)').each(function() {
var $hover = $(this).addClass('hover-bound'),
$msg = $hover.siblings('.dupe-hammer-message');
$hover.hover(
function() {
$hover.showInfoMessage('', {
messageElement: $msg.clone().show(),
transient: false,
position: { my: 'bottom left', at: 'top center', offsetTop: -7 },
dismissable: false,
relativeToBody: true
});
},
function() {
StackExchange.helpers.removeMessages();
}
);
});
});
Nov 15 '18 at 16:38
This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.
Is any error triggered? Can youconsole.log(err)
above thereturn user._id
?
– Cata John
Nov 13 '18 at 18:17
console.log response good id value, return - not.
– Adam Jakś
Nov 13 '18 at 19:25
add a comment |
This question already has an answer here:
How do I return the response from an asynchronous call?
33 answers
I need to fetch id of user from collection 'users' by calling a function and return it's value.
fetchId = (name) => {
User.findOne({name: name}, (err, user) => {
return user._id;
});
};
But this implementation returns null. What is the way to fix it?
javascript node.js mongodb
This question already has an answer here:
How do I return the response from an asynchronous call?
33 answers
I need to fetch id of user from collection 'users' by calling a function and return it's value.
fetchId = (name) => {
User.findOne({name: name}, (err, user) => {
return user._id;
});
};
But this implementation returns null. What is the way to fix it?
This question already has an answer here:
How do I return the response from an asynchronous call?
33 answers
javascript node.js mongodb
javascript node.js mongodb
asked Nov 13 '18 at 18:10
Adam JakśAdam Jakś
66
66
marked as duplicate by JohnnyHK
StackExchange.ready(function() {
if (StackExchange.options.isMobile) return;
$('.dupe-hammer-message-hover:not(.hover-bound)').each(function() {
var $hover = $(this).addClass('hover-bound'),
$msg = $hover.siblings('.dupe-hammer-message');
$hover.hover(
function() {
$hover.showInfoMessage('', {
messageElement: $msg.clone().show(),
transient: false,
position: { my: 'bottom left', at: 'top center', offsetTop: -7 },
dismissable: false,
relativeToBody: true
});
},
function() {
StackExchange.helpers.removeMessages();
}
);
});
});
Nov 15 '18 at 16:38
This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.
marked as duplicate by JohnnyHK
StackExchange.ready(function() {
if (StackExchange.options.isMobile) return;
$('.dupe-hammer-message-hover:not(.hover-bound)').each(function() {
var $hover = $(this).addClass('hover-bound'),
$msg = $hover.siblings('.dupe-hammer-message');
$hover.hover(
function() {
$hover.showInfoMessage('', {
messageElement: $msg.clone().show(),
transient: false,
position: { my: 'bottom left', at: 'top center', offsetTop: -7 },
dismissable: false,
relativeToBody: true
});
},
function() {
StackExchange.helpers.removeMessages();
}
);
});
});
Nov 15 '18 at 16:38
This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.
Is any error triggered? Can youconsole.log(err)
above thereturn user._id
?
– Cata John
Nov 13 '18 at 18:17
console.log response good id value, return - not.
– Adam Jakś
Nov 13 '18 at 19:25
add a comment |
Is any error triggered? Can youconsole.log(err)
above thereturn user._id
?
– Cata John
Nov 13 '18 at 18:17
console.log response good id value, return - not.
– Adam Jakś
Nov 13 '18 at 19:25
Is any error triggered? Can you
console.log(err)
above the return user._id
?– Cata John
Nov 13 '18 at 18:17
Is any error triggered? Can you
console.log(err)
above the return user._id
?– Cata John
Nov 13 '18 at 18:17
console.log response good id value, return - not.
– Adam Jakś
Nov 13 '18 at 19:25
console.log response good id value, return - not.
– Adam Jakś
Nov 13 '18 at 19:25
add a comment |
2 Answers
2
active
oldest
votes
following your example, if you don't want to use promises, you can simply pass a callback from the caller and invoke the callback when you have the result since the call to mongo is asynchronous.
fetchId = (name, clb) => {
User.findOne({name: name}, (err, user) => {
clb(user._id);
});
};
fetchId("John", id => console.log(id));
Otherwise you can use the promise based mechanism omitting the first callback and return the promise to the caller.
fetchId = name => {
return User.findOne({name: name}).then(user => user.id);
};
fetchId("John")
.then(id => console.log(id));
Ok, but how to use this first snippet with return value syntax? Ex. { creator_id: fetchId("Ian Corby", id => { /* return id */ } ) }
– Adam Jakś
Nov 13 '18 at 19:28
@AdamJakś - there are only two things that can be returned from a function (fetchId) whose result depends on an async call (findOne): (a) nothing, which is what your code and this answer's first idea returns, (b) a promise, which is this answer's second suggestion.
– danh
Nov 13 '18 at 20:21
@AdamJakś the promise suggestion is better, and once you master it, read up on async/away, which is a small improvement to promise that allows you to use the syntax I think you're looking for.
– danh
Nov 13 '18 at 20:22
@Karim from where you get user in user => user.id snippet? (second example) ;)
– Adam Jakś
Nov 15 '18 at 12:44
it's the result of the promise returned by User.findOne , after the call to the database
– Karim
Nov 15 '18 at 12:46
add a comment |
A third way is a variation of suggestion #2 in @Karim's (perfectly good) answer. If the OP wants to code it as if results are being assigned from async code, an improvement would be to declare fetchId as async
and await
its result...
fetchId = async (name) => {
return User.findOne({name: name}).then(user => user.id);
};
let someId = await fetchId("John");
console.log(id)
edit
For any method on an object -- including a property getter -- that works asynchronously, the calling code needs to be aware and act accordingly.
This tends to spread upward in your system to anything that depends on caller's callers, and so on. We can't avoid this, and there's no syntactic fix (syntax is what the compiler sees). It's physics: things that take longer, just take longer. We can use syntax to partially conceal the complexity, but we're stuck with the extra complexity.
Applying this to your question, say we have an object representing a User which is stored remotely by mongo. The simplest approach is to think of the in-memory user object as unready until an async fetch (findOne) operation has completed.
Under this approach, the caller has just one extra thing to remember: tell the unready user to get ready before using it. The code below employs async/await style syntax which is the the most modern and does the most to conceal -- but not eliminate :-( -- the async complexity...
class MyMongoUser {
// after new, this in-memory user is not ready
constructor(name) {
this.name = name;
this.mongoUser = null; // optional, see how we're not ready?
}
// callers must understand: before using, tell it to get ready!
async getReady() {
this.mongoUser = await myAsyncMongoGetter();
// if there are other properties that are computed asynchronously, do those here, too
}
async myAsyncMongoGetter() {
// call mongo
const self = this;
return User.findOne({name: self.name}).then(result => {
// grab the whole remote object. see below
self.mongoUser = result;
});
}
// the remaining methods can be synchronous, but callers must
// understand that these won't work until the object is ready
mongoId() {
return (this.mongoUser)? this.mongoUser._id : null;
}
posts() {
return [ { creator_id: this.mongoId() } ];
}
}
Notice, instead of just grabbing the mongo _id
from the user, we put away the whole mongo object. Unless this is a huge memory hog, we might as well have it hanging around so we can get any of the remotely stored properties.
Here's what the caller looks like...
let joe = new MyMongoUser('joe');
console.log(joe.posts()) // isn't ready, so this logs [ { creator_id: null } ];
await joe.getReady();
console.log(joe.posts()) // logs [ { creator_id: 'the mongo id' } ];
Yes, but the problem is I need to implement sytax like that: value = fetchId('John'); so function fetchId should RETURN value (console.log is working properly, but return - not) ;)
– Adam Jakś
Nov 14 '18 at 13:15
@AdamJakś - it can only return nothing or a promise to finish later. What it can't return is the result of findOne(), which hasn't run yet at the point fetchId returns. In the callback approach, it doesn't matter what the callback returns. The call back is called after findOne() runs.
– danh
Nov 14 '18 at 15:45
Ok, thank You for the explicit explaining. But - what if I need to use this function in value of property in Object? Just like: { posts [ { content: 'lorem', creator_id: <fetchId function use> } ]. Do You think it is possible? How to give the creator_id key the user id value? ;)
– Adam Jakś
Nov 15 '18 at 8:03
@AdamJakś - I understand what's troubling you. Please see the extensive amendment I made to the answer.
– danh
Nov 15 '18 at 16:56
Thanks you a lot for great explaining. I implemented this code by adding a function to value property, just like: posts:[ { creator_id: fetchId('john'); } ] and in the function body I added code from your caller's code proposition: async fetchId(name) { let john = new MyMongoUser(name); await john.getReady(); john.mongoId(); } And the problem is now that console returns me an error: Post validation failed: creator_id: Cast to String failed for value "Promise { <pending> }" at path "creat or_id" In post schema I have creator_id set as string. Parse string is not a sollution.
– Adam Jakś
Nov 16 '18 at 12:14
|
show 1 more comment
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
following your example, if you don't want to use promises, you can simply pass a callback from the caller and invoke the callback when you have the result since the call to mongo is asynchronous.
fetchId = (name, clb) => {
User.findOne({name: name}, (err, user) => {
clb(user._id);
});
};
fetchId("John", id => console.log(id));
Otherwise you can use the promise based mechanism omitting the first callback and return the promise to the caller.
fetchId = name => {
return User.findOne({name: name}).then(user => user.id);
};
fetchId("John")
.then(id => console.log(id));
Ok, but how to use this first snippet with return value syntax? Ex. { creator_id: fetchId("Ian Corby", id => { /* return id */ } ) }
– Adam Jakś
Nov 13 '18 at 19:28
@AdamJakś - there are only two things that can be returned from a function (fetchId) whose result depends on an async call (findOne): (a) nothing, which is what your code and this answer's first idea returns, (b) a promise, which is this answer's second suggestion.
– danh
Nov 13 '18 at 20:21
@AdamJakś the promise suggestion is better, and once you master it, read up on async/away, which is a small improvement to promise that allows you to use the syntax I think you're looking for.
– danh
Nov 13 '18 at 20:22
@Karim from where you get user in user => user.id snippet? (second example) ;)
– Adam Jakś
Nov 15 '18 at 12:44
it's the result of the promise returned by User.findOne , after the call to the database
– Karim
Nov 15 '18 at 12:46
add a comment |
following your example, if you don't want to use promises, you can simply pass a callback from the caller and invoke the callback when you have the result since the call to mongo is asynchronous.
fetchId = (name, clb) => {
User.findOne({name: name}, (err, user) => {
clb(user._id);
});
};
fetchId("John", id => console.log(id));
Otherwise you can use the promise based mechanism omitting the first callback and return the promise to the caller.
fetchId = name => {
return User.findOne({name: name}).then(user => user.id);
};
fetchId("John")
.then(id => console.log(id));
Ok, but how to use this first snippet with return value syntax? Ex. { creator_id: fetchId("Ian Corby", id => { /* return id */ } ) }
– Adam Jakś
Nov 13 '18 at 19:28
@AdamJakś - there are only two things that can be returned from a function (fetchId) whose result depends on an async call (findOne): (a) nothing, which is what your code and this answer's first idea returns, (b) a promise, which is this answer's second suggestion.
– danh
Nov 13 '18 at 20:21
@AdamJakś the promise suggestion is better, and once you master it, read up on async/away, which is a small improvement to promise that allows you to use the syntax I think you're looking for.
– danh
Nov 13 '18 at 20:22
@Karim from where you get user in user => user.id snippet? (second example) ;)
– Adam Jakś
Nov 15 '18 at 12:44
it's the result of the promise returned by User.findOne , after the call to the database
– Karim
Nov 15 '18 at 12:46
add a comment |
following your example, if you don't want to use promises, you can simply pass a callback from the caller and invoke the callback when you have the result since the call to mongo is asynchronous.
fetchId = (name, clb) => {
User.findOne({name: name}, (err, user) => {
clb(user._id);
});
};
fetchId("John", id => console.log(id));
Otherwise you can use the promise based mechanism omitting the first callback and return the promise to the caller.
fetchId = name => {
return User.findOne({name: name}).then(user => user.id);
};
fetchId("John")
.then(id => console.log(id));
following your example, if you don't want to use promises, you can simply pass a callback from the caller and invoke the callback when you have the result since the call to mongo is asynchronous.
fetchId = (name, clb) => {
User.findOne({name: name}, (err, user) => {
clb(user._id);
});
};
fetchId("John", id => console.log(id));
Otherwise you can use the promise based mechanism omitting the first callback and return the promise to the caller.
fetchId = name => {
return User.findOne({name: name}).then(user => user.id);
};
fetchId("John")
.then(id => console.log(id));
answered Nov 13 '18 at 18:20
KarimKarim
5,0691720
5,0691720
Ok, but how to use this first snippet with return value syntax? Ex. { creator_id: fetchId("Ian Corby", id => { /* return id */ } ) }
– Adam Jakś
Nov 13 '18 at 19:28
@AdamJakś - there are only two things that can be returned from a function (fetchId) whose result depends on an async call (findOne): (a) nothing, which is what your code and this answer's first idea returns, (b) a promise, which is this answer's second suggestion.
– danh
Nov 13 '18 at 20:21
@AdamJakś the promise suggestion is better, and once you master it, read up on async/away, which is a small improvement to promise that allows you to use the syntax I think you're looking for.
– danh
Nov 13 '18 at 20:22
@Karim from where you get user in user => user.id snippet? (second example) ;)
– Adam Jakś
Nov 15 '18 at 12:44
it's the result of the promise returned by User.findOne , after the call to the database
– Karim
Nov 15 '18 at 12:46
add a comment |
Ok, but how to use this first snippet with return value syntax? Ex. { creator_id: fetchId("Ian Corby", id => { /* return id */ } ) }
– Adam Jakś
Nov 13 '18 at 19:28
@AdamJakś - there are only two things that can be returned from a function (fetchId) whose result depends on an async call (findOne): (a) nothing, which is what your code and this answer's first idea returns, (b) a promise, which is this answer's second suggestion.
– danh
Nov 13 '18 at 20:21
@AdamJakś the promise suggestion is better, and once you master it, read up on async/away, which is a small improvement to promise that allows you to use the syntax I think you're looking for.
– danh
Nov 13 '18 at 20:22
@Karim from where you get user in user => user.id snippet? (second example) ;)
– Adam Jakś
Nov 15 '18 at 12:44
it's the result of the promise returned by User.findOne , after the call to the database
– Karim
Nov 15 '18 at 12:46
Ok, but how to use this first snippet with return value syntax? Ex. { creator_id: fetchId("Ian Corby", id => { /* return id */ } ) }
– Adam Jakś
Nov 13 '18 at 19:28
Ok, but how to use this first snippet with return value syntax? Ex. { creator_id: fetchId("Ian Corby", id => { /* return id */ } ) }
– Adam Jakś
Nov 13 '18 at 19:28
@AdamJakś - there are only two things that can be returned from a function (fetchId) whose result depends on an async call (findOne): (a) nothing, which is what your code and this answer's first idea returns, (b) a promise, which is this answer's second suggestion.
– danh
Nov 13 '18 at 20:21
@AdamJakś - there are only two things that can be returned from a function (fetchId) whose result depends on an async call (findOne): (a) nothing, which is what your code and this answer's first idea returns, (b) a promise, which is this answer's second suggestion.
– danh
Nov 13 '18 at 20:21
@AdamJakś the promise suggestion is better, and once you master it, read up on async/away, which is a small improvement to promise that allows you to use the syntax I think you're looking for.
– danh
Nov 13 '18 at 20:22
@AdamJakś the promise suggestion is better, and once you master it, read up on async/away, which is a small improvement to promise that allows you to use the syntax I think you're looking for.
– danh
Nov 13 '18 at 20:22
@Karim from where you get user in user => user.id snippet? (second example) ;)
– Adam Jakś
Nov 15 '18 at 12:44
@Karim from where you get user in user => user.id snippet? (second example) ;)
– Adam Jakś
Nov 15 '18 at 12:44
it's the result of the promise returned by User.findOne , after the call to the database
– Karim
Nov 15 '18 at 12:46
it's the result of the promise returned by User.findOne , after the call to the database
– Karim
Nov 15 '18 at 12:46
add a comment |
A third way is a variation of suggestion #2 in @Karim's (perfectly good) answer. If the OP wants to code it as if results are being assigned from async code, an improvement would be to declare fetchId as async
and await
its result...
fetchId = async (name) => {
return User.findOne({name: name}).then(user => user.id);
};
let someId = await fetchId("John");
console.log(id)
edit
For any method on an object -- including a property getter -- that works asynchronously, the calling code needs to be aware and act accordingly.
This tends to spread upward in your system to anything that depends on caller's callers, and so on. We can't avoid this, and there's no syntactic fix (syntax is what the compiler sees). It's physics: things that take longer, just take longer. We can use syntax to partially conceal the complexity, but we're stuck with the extra complexity.
Applying this to your question, say we have an object representing a User which is stored remotely by mongo. The simplest approach is to think of the in-memory user object as unready until an async fetch (findOne) operation has completed.
Under this approach, the caller has just one extra thing to remember: tell the unready user to get ready before using it. The code below employs async/await style syntax which is the the most modern and does the most to conceal -- but not eliminate :-( -- the async complexity...
class MyMongoUser {
// after new, this in-memory user is not ready
constructor(name) {
this.name = name;
this.mongoUser = null; // optional, see how we're not ready?
}
// callers must understand: before using, tell it to get ready!
async getReady() {
this.mongoUser = await myAsyncMongoGetter();
// if there are other properties that are computed asynchronously, do those here, too
}
async myAsyncMongoGetter() {
// call mongo
const self = this;
return User.findOne({name: self.name}).then(result => {
// grab the whole remote object. see below
self.mongoUser = result;
});
}
// the remaining methods can be synchronous, but callers must
// understand that these won't work until the object is ready
mongoId() {
return (this.mongoUser)? this.mongoUser._id : null;
}
posts() {
return [ { creator_id: this.mongoId() } ];
}
}
Notice, instead of just grabbing the mongo _id
from the user, we put away the whole mongo object. Unless this is a huge memory hog, we might as well have it hanging around so we can get any of the remotely stored properties.
Here's what the caller looks like...
let joe = new MyMongoUser('joe');
console.log(joe.posts()) // isn't ready, so this logs [ { creator_id: null } ];
await joe.getReady();
console.log(joe.posts()) // logs [ { creator_id: 'the mongo id' } ];
Yes, but the problem is I need to implement sytax like that: value = fetchId('John'); so function fetchId should RETURN value (console.log is working properly, but return - not) ;)
– Adam Jakś
Nov 14 '18 at 13:15
@AdamJakś - it can only return nothing or a promise to finish later. What it can't return is the result of findOne(), which hasn't run yet at the point fetchId returns. In the callback approach, it doesn't matter what the callback returns. The call back is called after findOne() runs.
– danh
Nov 14 '18 at 15:45
Ok, thank You for the explicit explaining. But - what if I need to use this function in value of property in Object? Just like: { posts [ { content: 'lorem', creator_id: <fetchId function use> } ]. Do You think it is possible? How to give the creator_id key the user id value? ;)
– Adam Jakś
Nov 15 '18 at 8:03
@AdamJakś - I understand what's troubling you. Please see the extensive amendment I made to the answer.
– danh
Nov 15 '18 at 16:56
Thanks you a lot for great explaining. I implemented this code by adding a function to value property, just like: posts:[ { creator_id: fetchId('john'); } ] and in the function body I added code from your caller's code proposition: async fetchId(name) { let john = new MyMongoUser(name); await john.getReady(); john.mongoId(); } And the problem is now that console returns me an error: Post validation failed: creator_id: Cast to String failed for value "Promise { <pending> }" at path "creat or_id" In post schema I have creator_id set as string. Parse string is not a sollution.
– Adam Jakś
Nov 16 '18 at 12:14
|
show 1 more comment
A third way is a variation of suggestion #2 in @Karim's (perfectly good) answer. If the OP wants to code it as if results are being assigned from async code, an improvement would be to declare fetchId as async
and await
its result...
fetchId = async (name) => {
return User.findOne({name: name}).then(user => user.id);
};
let someId = await fetchId("John");
console.log(id)
edit
For any method on an object -- including a property getter -- that works asynchronously, the calling code needs to be aware and act accordingly.
This tends to spread upward in your system to anything that depends on caller's callers, and so on. We can't avoid this, and there's no syntactic fix (syntax is what the compiler sees). It's physics: things that take longer, just take longer. We can use syntax to partially conceal the complexity, but we're stuck with the extra complexity.
Applying this to your question, say we have an object representing a User which is stored remotely by mongo. The simplest approach is to think of the in-memory user object as unready until an async fetch (findOne) operation has completed.
Under this approach, the caller has just one extra thing to remember: tell the unready user to get ready before using it. The code below employs async/await style syntax which is the the most modern and does the most to conceal -- but not eliminate :-( -- the async complexity...
class MyMongoUser {
// after new, this in-memory user is not ready
constructor(name) {
this.name = name;
this.mongoUser = null; // optional, see how we're not ready?
}
// callers must understand: before using, tell it to get ready!
async getReady() {
this.mongoUser = await myAsyncMongoGetter();
// if there are other properties that are computed asynchronously, do those here, too
}
async myAsyncMongoGetter() {
// call mongo
const self = this;
return User.findOne({name: self.name}).then(result => {
// grab the whole remote object. see below
self.mongoUser = result;
});
}
// the remaining methods can be synchronous, but callers must
// understand that these won't work until the object is ready
mongoId() {
return (this.mongoUser)? this.mongoUser._id : null;
}
posts() {
return [ { creator_id: this.mongoId() } ];
}
}
Notice, instead of just grabbing the mongo _id
from the user, we put away the whole mongo object. Unless this is a huge memory hog, we might as well have it hanging around so we can get any of the remotely stored properties.
Here's what the caller looks like...
let joe = new MyMongoUser('joe');
console.log(joe.posts()) // isn't ready, so this logs [ { creator_id: null } ];
await joe.getReady();
console.log(joe.posts()) // logs [ { creator_id: 'the mongo id' } ];
Yes, but the problem is I need to implement sytax like that: value = fetchId('John'); so function fetchId should RETURN value (console.log is working properly, but return - not) ;)
– Adam Jakś
Nov 14 '18 at 13:15
@AdamJakś - it can only return nothing or a promise to finish later. What it can't return is the result of findOne(), which hasn't run yet at the point fetchId returns. In the callback approach, it doesn't matter what the callback returns. The call back is called after findOne() runs.
– danh
Nov 14 '18 at 15:45
Ok, thank You for the explicit explaining. But - what if I need to use this function in value of property in Object? Just like: { posts [ { content: 'lorem', creator_id: <fetchId function use> } ]. Do You think it is possible? How to give the creator_id key the user id value? ;)
– Adam Jakś
Nov 15 '18 at 8:03
@AdamJakś - I understand what's troubling you. Please see the extensive amendment I made to the answer.
– danh
Nov 15 '18 at 16:56
Thanks you a lot for great explaining. I implemented this code by adding a function to value property, just like: posts:[ { creator_id: fetchId('john'); } ] and in the function body I added code from your caller's code proposition: async fetchId(name) { let john = new MyMongoUser(name); await john.getReady(); john.mongoId(); } And the problem is now that console returns me an error: Post validation failed: creator_id: Cast to String failed for value "Promise { <pending> }" at path "creat or_id" In post schema I have creator_id set as string. Parse string is not a sollution.
– Adam Jakś
Nov 16 '18 at 12:14
|
show 1 more comment
A third way is a variation of suggestion #2 in @Karim's (perfectly good) answer. If the OP wants to code it as if results are being assigned from async code, an improvement would be to declare fetchId as async
and await
its result...
fetchId = async (name) => {
return User.findOne({name: name}).then(user => user.id);
};
let someId = await fetchId("John");
console.log(id)
edit
For any method on an object -- including a property getter -- that works asynchronously, the calling code needs to be aware and act accordingly.
This tends to spread upward in your system to anything that depends on caller's callers, and so on. We can't avoid this, and there's no syntactic fix (syntax is what the compiler sees). It's physics: things that take longer, just take longer. We can use syntax to partially conceal the complexity, but we're stuck with the extra complexity.
Applying this to your question, say we have an object representing a User which is stored remotely by mongo. The simplest approach is to think of the in-memory user object as unready until an async fetch (findOne) operation has completed.
Under this approach, the caller has just one extra thing to remember: tell the unready user to get ready before using it. The code below employs async/await style syntax which is the the most modern and does the most to conceal -- but not eliminate :-( -- the async complexity...
class MyMongoUser {
// after new, this in-memory user is not ready
constructor(name) {
this.name = name;
this.mongoUser = null; // optional, see how we're not ready?
}
// callers must understand: before using, tell it to get ready!
async getReady() {
this.mongoUser = await myAsyncMongoGetter();
// if there are other properties that are computed asynchronously, do those here, too
}
async myAsyncMongoGetter() {
// call mongo
const self = this;
return User.findOne({name: self.name}).then(result => {
// grab the whole remote object. see below
self.mongoUser = result;
});
}
// the remaining methods can be synchronous, but callers must
// understand that these won't work until the object is ready
mongoId() {
return (this.mongoUser)? this.mongoUser._id : null;
}
posts() {
return [ { creator_id: this.mongoId() } ];
}
}
Notice, instead of just grabbing the mongo _id
from the user, we put away the whole mongo object. Unless this is a huge memory hog, we might as well have it hanging around so we can get any of the remotely stored properties.
Here's what the caller looks like...
let joe = new MyMongoUser('joe');
console.log(joe.posts()) // isn't ready, so this logs [ { creator_id: null } ];
await joe.getReady();
console.log(joe.posts()) // logs [ { creator_id: 'the mongo id' } ];
A third way is a variation of suggestion #2 in @Karim's (perfectly good) answer. If the OP wants to code it as if results are being assigned from async code, an improvement would be to declare fetchId as async
and await
its result...
fetchId = async (name) => {
return User.findOne({name: name}).then(user => user.id);
};
let someId = await fetchId("John");
console.log(id)
edit
For any method on an object -- including a property getter -- that works asynchronously, the calling code needs to be aware and act accordingly.
This tends to spread upward in your system to anything that depends on caller's callers, and so on. We can't avoid this, and there's no syntactic fix (syntax is what the compiler sees). It's physics: things that take longer, just take longer. We can use syntax to partially conceal the complexity, but we're stuck with the extra complexity.
Applying this to your question, say we have an object representing a User which is stored remotely by mongo. The simplest approach is to think of the in-memory user object as unready until an async fetch (findOne) operation has completed.
Under this approach, the caller has just one extra thing to remember: tell the unready user to get ready before using it. The code below employs async/await style syntax which is the the most modern and does the most to conceal -- but not eliminate :-( -- the async complexity...
class MyMongoUser {
// after new, this in-memory user is not ready
constructor(name) {
this.name = name;
this.mongoUser = null; // optional, see how we're not ready?
}
// callers must understand: before using, tell it to get ready!
async getReady() {
this.mongoUser = await myAsyncMongoGetter();
// if there are other properties that are computed asynchronously, do those here, too
}
async myAsyncMongoGetter() {
// call mongo
const self = this;
return User.findOne({name: self.name}).then(result => {
// grab the whole remote object. see below
self.mongoUser = result;
});
}
// the remaining methods can be synchronous, but callers must
// understand that these won't work until the object is ready
mongoId() {
return (this.mongoUser)? this.mongoUser._id : null;
}
posts() {
return [ { creator_id: this.mongoId() } ];
}
}
Notice, instead of just grabbing the mongo _id
from the user, we put away the whole mongo object. Unless this is a huge memory hog, we might as well have it hanging around so we can get any of the remotely stored properties.
Here's what the caller looks like...
let joe = new MyMongoUser('joe');
console.log(joe.posts()) // isn't ready, so this logs [ { creator_id: null } ];
await joe.getReady();
console.log(joe.posts()) // logs [ { creator_id: 'the mongo id' } ];
edited Nov 16 '18 at 19:46
answered Nov 13 '18 at 20:31
danhdanh
48.9k976113
48.9k976113
Yes, but the problem is I need to implement sytax like that: value = fetchId('John'); so function fetchId should RETURN value (console.log is working properly, but return - not) ;)
– Adam Jakś
Nov 14 '18 at 13:15
@AdamJakś - it can only return nothing or a promise to finish later. What it can't return is the result of findOne(), which hasn't run yet at the point fetchId returns. In the callback approach, it doesn't matter what the callback returns. The call back is called after findOne() runs.
– danh
Nov 14 '18 at 15:45
Ok, thank You for the explicit explaining. But - what if I need to use this function in value of property in Object? Just like: { posts [ { content: 'lorem', creator_id: <fetchId function use> } ]. Do You think it is possible? How to give the creator_id key the user id value? ;)
– Adam Jakś
Nov 15 '18 at 8:03
@AdamJakś - I understand what's troubling you. Please see the extensive amendment I made to the answer.
– danh
Nov 15 '18 at 16:56
Thanks you a lot for great explaining. I implemented this code by adding a function to value property, just like: posts:[ { creator_id: fetchId('john'); } ] and in the function body I added code from your caller's code proposition: async fetchId(name) { let john = new MyMongoUser(name); await john.getReady(); john.mongoId(); } And the problem is now that console returns me an error: Post validation failed: creator_id: Cast to String failed for value "Promise { <pending> }" at path "creat or_id" In post schema I have creator_id set as string. Parse string is not a sollution.
– Adam Jakś
Nov 16 '18 at 12:14
|
show 1 more comment
Yes, but the problem is I need to implement sytax like that: value = fetchId('John'); so function fetchId should RETURN value (console.log is working properly, but return - not) ;)
– Adam Jakś
Nov 14 '18 at 13:15
@AdamJakś - it can only return nothing or a promise to finish later. What it can't return is the result of findOne(), which hasn't run yet at the point fetchId returns. In the callback approach, it doesn't matter what the callback returns. The call back is called after findOne() runs.
– danh
Nov 14 '18 at 15:45
Ok, thank You for the explicit explaining. But - what if I need to use this function in value of property in Object? Just like: { posts [ { content: 'lorem', creator_id: <fetchId function use> } ]. Do You think it is possible? How to give the creator_id key the user id value? ;)
– Adam Jakś
Nov 15 '18 at 8:03
@AdamJakś - I understand what's troubling you. Please see the extensive amendment I made to the answer.
– danh
Nov 15 '18 at 16:56
Thanks you a lot for great explaining. I implemented this code by adding a function to value property, just like: posts:[ { creator_id: fetchId('john'); } ] and in the function body I added code from your caller's code proposition: async fetchId(name) { let john = new MyMongoUser(name); await john.getReady(); john.mongoId(); } And the problem is now that console returns me an error: Post validation failed: creator_id: Cast to String failed for value "Promise { <pending> }" at path "creat or_id" In post schema I have creator_id set as string. Parse string is not a sollution.
– Adam Jakś
Nov 16 '18 at 12:14
Yes, but the problem is I need to implement sytax like that: value = fetchId('John'); so function fetchId should RETURN value (console.log is working properly, but return - not) ;)
– Adam Jakś
Nov 14 '18 at 13:15
Yes, but the problem is I need to implement sytax like that: value = fetchId('John'); so function fetchId should RETURN value (console.log is working properly, but return - not) ;)
– Adam Jakś
Nov 14 '18 at 13:15
@AdamJakś - it can only return nothing or a promise to finish later. What it can't return is the result of findOne(), which hasn't run yet at the point fetchId returns. In the callback approach, it doesn't matter what the callback returns. The call back is called after findOne() runs.
– danh
Nov 14 '18 at 15:45
@AdamJakś - it can only return nothing or a promise to finish later. What it can't return is the result of findOne(), which hasn't run yet at the point fetchId returns. In the callback approach, it doesn't matter what the callback returns. The call back is called after findOne() runs.
– danh
Nov 14 '18 at 15:45
Ok, thank You for the explicit explaining. But - what if I need to use this function in value of property in Object? Just like: { posts [ { content: 'lorem', creator_id: <fetchId function use> } ]. Do You think it is possible? How to give the creator_id key the user id value? ;)
– Adam Jakś
Nov 15 '18 at 8:03
Ok, thank You for the explicit explaining. But - what if I need to use this function in value of property in Object? Just like: { posts [ { content: 'lorem', creator_id: <fetchId function use> } ]. Do You think it is possible? How to give the creator_id key the user id value? ;)
– Adam Jakś
Nov 15 '18 at 8:03
@AdamJakś - I understand what's troubling you. Please see the extensive amendment I made to the answer.
– danh
Nov 15 '18 at 16:56
@AdamJakś - I understand what's troubling you. Please see the extensive amendment I made to the answer.
– danh
Nov 15 '18 at 16:56
Thanks you a lot for great explaining. I implemented this code by adding a function to value property, just like: posts:[ { creator_id: fetchId('john'); } ] and in the function body I added code from your caller's code proposition: async fetchId(name) { let john = new MyMongoUser(name); await john.getReady(); john.mongoId(); } And the problem is now that console returns me an error: Post validation failed: creator_id: Cast to String failed for value "Promise { <pending> }" at path "creat or_id" In post schema I have creator_id set as string. Parse string is not a sollution.
– Adam Jakś
Nov 16 '18 at 12:14
Thanks you a lot for great explaining. I implemented this code by adding a function to value property, just like: posts:[ { creator_id: fetchId('john'); } ] and in the function body I added code from your caller's code proposition: async fetchId(name) { let john = new MyMongoUser(name); await john.getReady(); john.mongoId(); } And the problem is now that console returns me an error: Post validation failed: creator_id: Cast to String failed for value "Promise { <pending> }" at path "creat or_id" In post schema I have creator_id set as string. Parse string is not a sollution.
– Adam Jakś
Nov 16 '18 at 12:14
|
show 1 more comment
Is any error triggered? Can you
console.log(err)
above thereturn user._id
?– Cata John
Nov 13 '18 at 18:17
console.log response good id value, return - not.
– Adam Jakś
Nov 13 '18 at 19:25