Проверьте, существует ли документ в mongodb, используя es7 async/await

Я пытаюсь проверить, существует ли пользователь с предоставленным email в коллекции users, но моя функция продолжает возвращать неопределенное значение для каждого вызова. Я использую es6 и async/await, чтобы избавиться от множества обратных вызовов. Вот моя функция (она находится внутри класса):

async userExistsInDB(email) {
    let userExists;
    await MongoClient.connect('mongodb://127.0.0.1:27017/notificator', (err, db) => {
        if (err) throw err;

        let collection = db.collection('users');

        userExists = collection.find({email: email}).count() > 0;
        console.log(userExists);

        db.close();
    });
    console.log(userExists);
    return userExists;
}

Таким образом, первый console.log внутри вызова .connect всегда возвращает false, потому что возвращаемое значение .find не является массивом, это какой-то огромный объект, который выглядит так:

{ connection: null,
  server: null,
  disconnectHandler: 
   { s: { storedOps: [], storeOptions: [Object], topology: [Object] },
     length: [Getter] },
  bson: {},
  ns: 'notificator.users',
  cmd: 
   { find: 'notificator.users',
     limit: 0,
     skip: 0,
     query: { email: '[email protected]' },
     slaveOk: true,
     readPreference: { preference: 'primary', tags: undefined, options: undefined } },
  options: 
........
........

И последний console.log всегда undefined (хотя я думаю, что так быть не должно, ведь await ждёт окончания асинхронного вызова, да?)


Мне просто нужно, чтобы моя функция возвращала логическое значение, а не Promise или что-то в этом роде.

Может ли кто-нибудь помочь мне с этим?

ОБНОВЛЕНИЕ 1

console.log(collection.findOne({email: email})); внутри .connect возвращает это:

 { 'Symbol(record)_3.ugi5lye6fvq5b3xr': 
   { p: [Circular],
     c: [],
     a: undefined,
     s: 0,
     d: false,
     v: undefined,
     h: false,
     n: false } }

ОБНОВЛЕНИЕ 2

Похоже, это было связано с моим плохим знанием es7 async/await.

Теперь код внутри .connect возвращает нужное значение.

async userExistsInDB(email) {
    let userExists;
    await* MongoClient.connect('mongodb://127.0.0.1:27017/notificator', async(err, db) => {
        if (err) throw err;

        let collection = db.collection('users');
        userExists = await collection.find({email: email}).limit(1).count() > 0;

        db.close();
    });
    console.log(userExists); // <--- this is not called at all
    return userExists;
}

Однако теперь вызов console.log или что-либо после вызова .connect вообще не выполняется.

Теперь каждый раз, когда я где-то вызываю функцию userExistsInDB() и console.log ее результат, я получаю следующее:

 { 'Symbol(record)_3.78lmjnx8e3766r': 
   { p: [Circular],
     c: [],
     a: undefined,
     s: 0,
     d: false,
     v: undefined,
     h: false,
     n: false } }

Есть идеи, почему это так?


person Denis Yakovenko    schedule 31.10.2015    source источник
comment
Не используйте count(), вы просите mongodb продолжать подсчет даже после того, как будет найден первый такой документ. Просто используйте findOne() и посмотрите, вернет ли он что-нибудь с тем же email.   -  person S.D.    schedule 31.10.2015
comment
Пожалуйста, смотрите обновление. Кстати, я где-то читал, что использование findOne() намного медленнее, чем использование find().limit(1), что бы вы сказали по этому поводу?   -  person Denis Yakovenko    schedule 31.10.2015
comment
@Dennis find().limit(1).count() действительно хорошая оптимизация. Драйвер JavaScript для монго автоматически делает это в его findOne() реализации.   -  person S.D.    schedule 31.10.2015


Ответы (1)


Хорошо, вот как я заработал:

async function userExistsInDB(email, password) {
    let db = await MongoClient.connect('mongodb://127.0.0.1:27017/notificator');
    try {
        let collection = db.collection('users');
        let userCount = (await collection.find(
            {
                email: email,
                password: password
            }).limit(1).count());
        return userCount > 0;
    } finally {
        db.close();
    }
}

А поскольку ключевое слово async в объявлении функции гарантирует, что возвращаемое значение будет Promise, единственный способ получить реальный возвращаемый результат из этой функции:

let result = await this.userExistsInDB(email, password); внутри другой функции, объявленной async.

person Denis Yakovenko    schedule 02.11.2015
comment
полезная @заметка себе :) - person dcsan; 01.01.2016