Javascript Mongodb findOne-返回值

Javascript Mongodb findOne-返回值,javascript,node.js,mongodb,Javascript,Node.js,Mongodb,我需要通过调用函数从集合“users”中获取用户id并返回其值 fetchId = (name) => { User.findOne({name: name}, (err, user) => { return user._id; }); }; 但是这个实现返回null。修复方法是什么?按照您的示例,如果您不想使用承诺,您可以简单地从调用方传递回调,并在得到结果时调用回调,因为对mongo的调用是异步的 fetchId

我需要通过调用函数从集合“users”中获取用户id并返回其值

fetchId = (name) => {
        User.findOne({name: name}, (err, user) => {
            return user._id;
        });
    };

但是这个实现返回null。修复方法是什么?

按照您的示例,如果您不想使用承诺,您可以简单地从调用方传递回调,并在得到结果时调用回调,因为对mongo的调用是异步的

fetchId = (name, clb) => {
  User.findOne({name: name}, (err, user) => {
    clb(user._id);
  });
};

fetchId("John", id => console.log(id));
否则,可以使用基于承诺的机制忽略第一个回调,并将承诺返回给调用方

fetchId = name => {
  return User.findOne({name: name}).then(user => user.id);
}; 


fetchId("John")
 .then(id => console.log(id));

第三种方法是@Karim(非常好)答案中建议2的变体。如果OP希望将其编码为结果是从异步代码分配的,那么改进方法是将fetchId声明为
async
wait
其结果

fetchId = async (name) => {
    return User.findOne({name: name}).then(user => user.id);
};

let someId = await fetchId("John");
console.log(id)
编辑

对于对象上异步工作的任何方法(包括属性getter),调用代码都需要知道并相应地执行操作

这往往会在您的系统中向上扩展到依赖于调用方的调用方的任何东西,等等。我们无法避免这种情况,而且没有语法修复(语法是编译器看到的)。这是物理学:需要更长时间的东西,只是需要更长的时间。我们可以使用语法来部分隐藏复杂性,但我们会被额外的复杂性所困扰

将此应用于您的问题,假设我们有一个表示用户的对象,该用户由mongo远程存储。最简单的方法是在异步获取(findOne)操作完成之前,将内存中的用户对象视为未完成

在这种方法下,调用方只需记住一件额外的事情:告诉未准备好的用户在使用它之前做好准备。下面的代码使用了异步/等待样式的语法,这是最现代的语法,并且最大程度地隐藏了(但没有消除):(-)异步复杂性

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() } ];
    }
}
请注意,我们不只是从用户那里获取mongo
\u id
,而是将整个mongo对象放在一边。除非这是一个巨大的内存占用器,否则我们最好将其挂起,以便获得任何远程存储的属性

这是来电者的样子

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

是否触发了任何错误?能否在
返回用户上方
console.log(err)
?console.log响应良好的id值,返回-不是。确定,但如何使用返回值语法的第一个代码段?例如{creator\u id:fetchId(“Ian Corby”,id=>{/*返回id*/})@AdamJakś-函数(fetchId)的结果取决于异步调用(findOne),只能返回两个结果:(a)nothing,这是您的代码和此答案的第一个想法返回的结果,(b)承诺,这是这个答案的第二个建议。@AdamJakś承诺建议更好,一旦你掌握了它,请阅读async/away,这是对承诺的一个小小改进,允许你使用我认为你正在寻找的语法。@Karim从哪里获得user in user=>user.id片段?(第二个示例);)这是User.findOne在调用数据库后返回的承诺的结果是的,但问题是我需要像这样实现sytax:value=fetchId('John');所以函数fetchId应该返回值(console.log工作正常,但返回-not);)@AdamJakś-它只能什么也不回报,或者承诺以后完成。它不能返回的是findOne()的结果,该结果在fetchId返回点尚未运行。在回调方法中,回调返回什么并不重要。回调在findOne()运行后调用。好的,感谢您的明确解释。但是-若我需要在对象中的属性值中使用这个函数呢?就像:{posts[{content:'lorem',creator_id:}]。你认为有可能吗?如何给creator_id键用户id值?;)@AdamJakś-我理解你的问题。请看我对答案所做的大量修改。非常感谢你的精彩解释。我通过在value属性中添加一个函数来实现这段代码,就像:posts:[{creator_id:fetchId('john');}]在函数体中,我添加了来自调用方代码命题的代码:async fetchId(name){let john=new MyMongoUser(name);wait john.getReady();john.mongoId();},现在的问题是控制台返回了一个错误:验证后失败:creator_id:在路径“create or_id”处对值“Promise{}”转换为字符串失败在post模式中,我将creator_id设置为字符串。解析字符串不是解决方案。