Mongodb返回字符串数组而不是对象数组

时间:2014-10-23 19:59:55

标签: node.js mongodb mongoose

我使用此代码从mongo db(带有mongoose的nodejs)中的用户查询令牌:

UserMdl.find().exists('token').select('token').exec(function onUsersFound(err, userMdls) {
  console.log(userMdls);
});

所以我得到了:

[ { 
  _id: 5447e36a60e5d15678de486c,
  token: '34f83483cc0ed82e17c162d'
}, ... ]

有没有办法获得字符串数组:

[ '34f83483cc0ed82e17c162d', ... ]

现在我正在做的是对响应进行后期处理。我问这个问题是因为我认为在mongoose / mongodb查询中可能有更快的方法。

修改

后处理我现在正在做:

var results = [];
userMdls.forEach(function (userMdl) {
  results.push(userMdl.token);
});

修改

感谢saintedlama的回应,我做了一些测试,结果就是这样:

数据:14.976份文件
测试:100
结果:

.find().exists('token').exec(..):1236.33 ms
 .aggregate({..}):136.07 ms

测试代码:

  var start,
    end,
    time,
    firstTimes = [],
    secondTimes = [],
    test = 0,
    firstFinal,
    secondFinal,
    i,
    Q = require('q'),
    UserMdl = require('models/user'),
    u,
    tokens = [];


  function promiseWhile(condition, body) {
    var done = Q.defer();

    function repeatTest() {
      start = new Date().getTime();

      UserMdl.find().exists('token').exec(function onUserMdlFound(err, users) {
        for (u = 0; u < users.length; u += 1) {
          tokens.push(users[u].token);
        }

        end = new Date().getTime();
        time = end - start;
        firstTimes.push(time);
        start = new Date().getTime();
        tokens = [];

        UserMdl.aggregate({
          $match: {
            token: {
              $exists: true
            }
          }
        }, {
          $project: {
            _id: 0,
            token: 1
          }
        }, function onUserMdlFoundAggregate(err, users) {
          for (u = 0; u < users.length; u += 1) {
            tokens.push(users[u].token);
          }

          end = new Date().getTime();
          time = end - start;
          secondTimes.push(time);
          tokens = [];

          if (condition()) {
            Q.when(body(), repeatTest, done.reject);
          } else {
            return done.resolve();
          }
        });
      });
    }

    Q.nextTick(repeatTest);

    return done.promise;
  }


  function printResult() {
    firstFinal = 0;
    secondFinal = 0;
    for (i = 0; i < firstTimes.length; i += 1) {
      firstFinal += firstTimes[i];
      secondFinal += secondTimes[i];
    }
    console.log("First mean: " + firstFinal / i + " - Second mean: " + secondFinal / i);
  }

  test = 1;
  promiseWhile(function condition() {
    return test <= 300;
  }, function body() {
    console.log("running test: " + test);
    test++;
    return Q.delay(0); // arbitrary async

  }).then(function () {
    console.log("Finish testing");
    printResult();

  }).done();

2 个答案:

答案 0 :(得分:2)

有一种方法可以选择仅使用mongodb aggregation framework需要较少处理的令牌

UserMdl.aggregate(
  { $match: { token : { $exists : true }}},
  { $project: { _id: 0, token: 1 }},
  function onUsersFound(err, tokens) {
    console.log(tokens);
  });
);

这构造了一个聚合管道,该管道首先匹配具有令牌字段的所有文档,然后选择令牌字段并使用_id : 0管道步骤中的$project来抑制_id选择。

后处理步骤如下所示:

function postProcess(tokenObjects) {
  if (!tokenObjects) {
    return [];
  }

  return tokenObjects.map(function(tokenObject) { return tokenObject.token; });  
}

有关聚合函数的详细信息,另请参阅the mongoose docs

答案 1 :(得分:1)

您不需要执行任何特殊操作。只需更改代码中的一件事即可:

您的代码

UserMdl.find().exists('token').select('token').exec(function onUsersFound(err, userMdls) {
    console.log(userMdls);    // (*) Change this to...
});

更改

UserMdl.find().exec((err, users) => {
    console.log(users.map(user => user.token));    // ...(*) to this
});

无需使用selectexists函数


编辑

最好的选择是猫鼬distinct函数:

const tokens = await UserMdl.distinct('token');

如果您需要条件,那么:

const tokens = await UserMdl.find(/* condition */).distinct('token');

就这样