【问题标题】:MongoDB and NodeJS get related data from 3 collectionsMongoDB 和 NodeJS 从 3 个集合中获取相关数据
【发布时间】:2014-07-16 12:40:29
【问题描述】:

我有一个 mongoDB 查询来获取 $group 和 $count 的数据。 此数据包含来自其他文档集合的 _id。 如何在 NodeJS 和 MongoDB 异步中通过 _id 获取其他文档?

 db.orders.aggregate([
                 {$match: { 'works.TechnicianId': {$in:['53465f9d519c94680327965d','5383577a994be8b9a9e3f01e']}, 
                           'works.Date': {$gte: ISODate("2013-05-21T06:40:20.299Z"), $lt: ISODate("2016-05-21T06:40:20.299Z")}}},
                 {$unwind: "$works" },
                 {$group: {_id: "$works.TechnicianId",total:{$sum:'$works.price'},ordersId: { $push: "$_id" }}},
                   ])

这是结果:

    {
    "result" : [ 
        {
            "_id" : "53465f9d519c94680327965d",
            "total" : 198,
            "ordersId" : [ 
                ObjectId("537b5ea4c61b1d1743f4341f"), 
                ObjectId("537b4633021d75bd36863f29")
            ]
        }, 
        {
            "_id" : "5383577a994be8b9a9e3f01e",
            "total" : 22,
            "ordersId" : [ 
                ObjectId("537b5ea4c61b1d1743f4341f"), 
                ObjectId("537b4633021d75bd36863f29")
            ]
        }
    ],
    "ok" : 1
}

现在我需要从 orders 集合中获取 id 来自 ordersId 的文档,并从其他集合中获取来自结果 _id 字段的 _id 文档。

我试试这个:

var collection = db.collection('orders');
    var result = [];

    collection.aggregate([
            {
                $match: {
                    'works.TechnicianId': {
                        $in: ids
                    },
                    'works.Date': {
                        $gte: new Date(startDate),
                        $lt: new Date(endDate)
                    }
                }
            },
            {
                $unwind: "$works"
            },
            {
                $group: {
                    _id: "$works.TechnicianId",
                    total: {
                        $sum: '$works.price'
                    },
                    orderId: {
                        $push: "$_id"
                    }
                }
            }
        ],
        function (e, docs) {
            if (e) {
                error(e);
            }
            var usersCollection = db.collection('users');

            _.each(docs, function (doc) {
                usersCollection.findOne({_id: new ObjectID(doc._id)}, function (e, doc) {
                    doc.tech = doc;
                });
                doc.orders = [];
                _.each(doc.orderId, function (queryOrder) {
                    collection.findOne({_id: new ObjectID(queryOrder._id)}, function (e, order) {
                        doc.orders.push(order);
                    });
                });
                success(docs);
            });
        });

但是在所有 _.eachs 完成之前就调用了成功..有什么帮助或想法吗?

编辑:

我尝试使用 Q 承诺,这是我的代码:

 var usersCollection = db.collection('users');
            var promises = [];

            _.each(reports, function (report) {
                var promise = usersCollection.findOne({_id: new ObjectID(report._id)}).then(
                    function (e, orderUserReported) {
                        if (e) {
                            error(e);
                        }
                        report.tech = orderUserReported;
                        _.each(orderUserReported.orderId, function (queryOrder) {
                            collection.findOne({_id: new ObjectID(queryOrder._id)}, function (e, order) {
                                report.orders.push(order);
                            });
                        });
                    });
                promises.push(promise);
            });
            Q.allSettled(promises).then(success(reports));

和错误:

/Users/colymore/virteu/aa/server/node_modules/mongodb/lib/mongodb/connection/base.js:245
        throw message;      
              ^

TypeError: 无法调用未定义的方法 'then'

【问题讨论】:

    标签: node.js mongodb


    【解决方案1】:

    简答:使用承诺。看看 Q.allSettled (https://github.com/kriskowal/q) 在所有子任务完成后异步运行成功。

    如果你想在你的 mongo 中使用 mongoose,那么使用 https://github.com/iolo/mongoose-q 包可能有助于不将 mongoose 承诺与 Q 结合起来。

    【讨论】:

      【解决方案2】:

      由于异步执行,您必须等到返回结果。有几个选项可用:

      1. 异步库https://github.com/caolan/async
      2. 承诺https://github.com/kriskowal/q

      Async 更接近您当前的代码,您可以使用 async.parallel https://github.com/caolan/async#parallel 等到您取回数据

      更新

      Mongoose 函数不返回 Q 承诺,因此您需要使用 Q.denodeify(User.findOne.bind(models.User))({ _id: userId}).then(... 之类的东西将 mongoose 调用转换为承诺

      你的情况Q.denodeify(userCollection.findOne.bind(userCollection))({_id: new ObjectID(report._id)}).then(...

      【讨论】:

      • 但是如果我不使用猫鼬呢?我使用官方的 mongodb nodejs 库
      • 还是一样,看看Q.denodeify github.com/kriskowal/q/wiki/API-Reference。是将“回调函数”转换为返回promise的方法。
      • 谢谢,我会试试的。我来自 java EE,对我来说非常复杂
      猜你喜欢
      • 2013-02-14
      • 1970-01-01
      • 2019-01-13
      • 1970-01-01
      • 2020-05-13
      • 1970-01-01
      • 2023-02-02
      • 1970-01-01
      • 2022-11-06
      相关资源
      最近更新 更多