Как реализовать функцию отображения курсора Mongodb в node.js (node-mondodb-native)

Я пытаюсь реализовать следующий запрос MongoDB в NodeJS.

db.tvseries.find({}).map(function(doc){
    var userHasSubscribed = false;

    doc.followers && doc.followers.forEach(function(follower) {
            if(follower.$id == "abc") {
                userHasSubscribed = true;
            }
        });


    var followers = doc.followers && doc.followers.map(function(follower) {
            var followerObj;
            db[follower.$ref].find({
                    "_id" : follower.$id
                }).map(function(userObj) {
                        followerObj = userObj;
                    });
             return followerObj;
        });

    return {
            "id": doc.name,
            "userHasSubscribed": userHasSubscribed,
            "followers": followers || []
        };
})

Ниже приведена БД

коллекция пользователей

{
     "id": ObjectId("abc"),
     "name": "abc_name"
},
{
     "id": ObjectId("def"),
     "name": "def_name"
},
{
     "id": ObjectId("ijk"),
     "name": "ijk_name"
}

коллекция сериалов

{
     "id": ObjectId("123"),
     "name": "123_name",
     "followers": [
        {
            "$ref": "users",
            "$id": ObjectId("abc"),
        },
        {
            "$ref": "users",
            "$id": ObjectId("def"),
        }
     ]
},
{
     "id": ObjectId("456"),
     "name": "456_name",
     "followers": [
         {
            "$ref": "users",
            "$id": ObjectId("ijk"),
        },
     ]
},
{
     "id": ObjectId("789"),
     "name": "789_name"
}

Я не могу понять, как выполнить вышеуказанный запрос MongoDB в NodeJS с помощью node-mongodb -нативный плагин.

Я попробовал приведенный ниже код, но затем я получаю TypeError: undefined is not a function в .map.

var collection = db.collection('users');
collection.find({}).map(function(doc) {
   console.log(doc);
});

Как выполнить функцию .map в NodeJS?

заранее спасибо


person Sreedhar M B    schedule 30.03.2015    source источник


Ответы (4)


Я боролся с этим некоторое время. Я обнаружил это, добавив .toArray() после работы функции map.

Вы даже можете пропустить map и добавить только .toArray(), чтобы получить все поля документов.

  const accounts = await _db
    .collection('accounts')
    .find()
    .map(v => v._id) // leaving this out gets you all the fields
    .toArray();

  console.log(accounts); // [{_id: xxx}, {_id: xxx} ...]

Обратите внимание, что для того, чтобы map работала, используемая функция должна что-то возвращать — в вашем примере только console.log без возврата значения.


Решение forEach работает, но я действительно хотел, чтобы map работало.

person bamse    schedule 05.11.2017

Я знаю, что я довольно поздно, но я прибыл сюда, выполнив поиск в Google по той же проблеме. Наконец, я не смог использовать для этого функцию map, но с помощью forEach мне удалось это сделать.

Пример использования ES6 и StandardJS.

  let ids = []
  let PublicationId = ObjectID(id)
  feeds_collection
    .find({PublicationId})
    .project({ _id: 1 })
    .forEach((feed) => {
      ids.push(feed._id)
    }, () => done(ids))
person midudev    schedule 22.02.2016

Чтобы повторить ответ @bamse, я заработал с .toArray(). Вот асинхронный пример:

async function getWordArray (query) {
  const client = await MongoClient.connect(url)
  const collection = client.db('personal').collection('wordBank')
  const data = await collection.find(query).map(doc => doc.word).toArray()
  return data
}

Затем я использую его в своем экспресс-маршруте следующим образом:

app.get('/search/:fragment', asyncMiddleware(async (req, res, next) => {
  const result = await getWordArray({word: 'boat'})
  res.json(result)
}))

Наконец, если вам нужно руководство по промежуточному программному обеспечению async/await в NodeJS, вот руководство: https://medium.com/@Abazhenov/using-async-await-in-express-with-node-8-b8af872c0016

person JP Lew    schedule 27.01.2018

map возвращает курсор, toArray возвращает Promise, который выполнит курсор и вернет его результаты. Это может быть массив исходного запроса find, limit и т. д. или обещание массива результатов, переданных через функцию.

Обычно это полезно, когда вы хотите взять документы курсора и обработать их (возможно, получить что-то еще), пока курсор все еще извлекает документы, а не ждать, пока все они не будут загружены в память узла.

Рассмотрим пример

let foos = await db.collection("foos")
    .find()
    .project({
        barId: 1
    })
    .toArray() // returns a Promise<{barId: ObjectId}[]>

// we now have all foos into memory, time to get bars
let bars = await Promise.all(foos.map(doc => db
    .collection("bars")
    .findOne({
        _id: doc.barId
    })))

это примерно эквивалентно

bars = await db.collection("foos")
    .find()
    .project({
        barId: 1
    })
    .toArray() // returns a Promise<{barId: ObjectId}[]>
    .then(docs => docs
        .map(doc => db
            .collection("bars")
            .findOne({
                _id: doc.barId
            })))

используя map, вы можете выполнять операцию асинхронно и (надеюсь) более эффективно

bars = await db.collection("foos")
    .find()
    .project({
        barId: 1
    })
    .map(doc => db
        .collection("bars")
        .findOne({
            _id: doc.barId
        }))
    .toArray()
    .then(barPromises => Promise.all(barPromises)) // Promise<Bar[]>

Суть в том, что map — это просто функция, которая применяется к результатам, полученным курсором. Эта функция не будет выполняться до тех пор, пока вы не превратите ее в Promise, используя либо forEach, либо, что более разумно, map.

person CervEd    schedule 03.02.2021