Mongodb findOne - return value [duplicate]












0
















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?










share|improve this question













marked as duplicate by JohnnyHK javascript
Users with the  javascript badge can single-handedly close javascript questions as duplicates and reopen them as needed.

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 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
















0
















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?










share|improve this question













marked as duplicate by JohnnyHK javascript
Users with the  javascript badge can single-handedly close javascript questions as duplicates and reopen them as needed.

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 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














0












0








0









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?










share|improve this question















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






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 13 '18 at 18:10









Adam JakśAdam Jakś

66




66




marked as duplicate by JohnnyHK javascript
Users with the  javascript badge can single-handedly close javascript questions as duplicates and reopen them as needed.

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 javascript
Users with the  javascript badge can single-handedly close javascript questions as duplicates and reopen them as needed.

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 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



















  • 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

















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












2 Answers
2






active

oldest

votes


















2














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));





share|improve this answer
























  • 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



















0














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' } ];





share|improve this answer


























  • 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




















2 Answers
2






active

oldest

votes








2 Answers
2






active

oldest

votes









active

oldest

votes






active

oldest

votes









2














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));





share|improve this answer
























  • 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
















2














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));





share|improve this answer
























  • 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














2












2








2







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));





share|improve this answer













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));






share|improve this answer












share|improve this answer



share|improve this answer










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



















  • 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













0














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' } ];





share|improve this answer


























  • 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


















0














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' } ];





share|improve this answer


























  • 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
















0












0








0







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' } ];





share|improve this answer















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' } ];






share|improve this answer














share|improve this answer



share|improve this answer








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





















  • 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





Popular posts from this blog

Florida Star v. B. J. F.

Error while running script in elastic search , gateway timeout

Adding quotations to stringified JSON object values