2

我正在使用 Node/Express/MongoDB/Mongoskin 构建一个应用程序。

在数据库中,我有一个名为“clients”的集合,其中包含有关客户帐户信息的文档。每个客户文档都包含一个包含发票对象的数组,如下所示:

doc.invoices = [
  {year: 2012,
  quarter: 1, 
  daily: 912.00, 
  sms: 42.00, 
  paid: true},

  {year: 2012,
  quarter: 2, 
  daily: 913.00, 
  sms: 55.00, 
  paid: true}, 

  {year: 2012,
  quarter: 3, 
  daily: 876.00, 
  sms: 82.00, 
  paid: true}, 

  {year: 2012,
  quarter: 4, 
  daily: 903.00, 
  sms: 93.00, 
  paid: false},

  {year: 2013,
  quarter: 1, 
  daily: 915.00, 
  sms: 67.00, 
  paid: true},

  {year: 2013,
  quarter: 2, 
  daily: 920.00, 
  sms: 35.00, 
  paid: true}, 

  {year: 2013,
  quarter: 3, 
  daily: 880.00, 
  sms: 92.00, 
  paid: true}, 

  {year: 2013,
  quarter: 4, 
  daily: 900.00, 
  sms: 85.00, 
  paid: false}
]

问题:假设我想查询此集合中的所有文档,例如在显示所有客户端的超级管理员视图中,但我想将从发票数组返回的信息限制为“年份”等于某个值的对象,例如 2013 年,当前年份。

我想投影是我需要的,但问题是投影只返回它找到的第一个结果......

4

4 回答 4

6

首先,投影不会返回它找到的第一个结果,它会告诉 mongo 要返回什么。

.findOne(query) 会将结果限制为一个,或者 find(query).limit(1) 也会这样做。

您说您正在尝试“获取所有”数据。

一个标准的查找类型查询将让你开始......

find({mongo:query},{mongo:projection})

但将结果限制为来自 mongo shell* 的游标

既然你说你使用 express.js,你可以使用 javascript 函数来“返回所有”这样一个简单查找的结果......

db.sales.find({"year":2013},{_id:0,"year":1,"quarter":1,"daily":1,"sms":1,"paid":1}) 

首先设置一个函数的路由

app.get('/sales/yr/:yr', sales.getAllResults);

然后是一个函数来处理您的简单 mongo 查询和投影。

/**
 *  get ALL results given YEAR ONLY
 *  extend jsonQuery to modify results
 *  extend or reduce jsonProjection to control data returned
 */
exports.getAllResults= function(req, res) {
    var yr = req.params.yr ;    
    var jsonQuery = {"year":yr} ;  //add or remove comma seperated "key":values given your JSON collection
    var jsonProjection = {_id:0,"year":1,"quarter":1,"daily":1,"sms":1,"paid":1} ; //leave year out since that's specified in the query anyhow
    var jsort = {"some-thing-else":-1} ; //-1 descending or 1 ascending
    db.collection("YOUR-COLLECTION_NAME", function(err, collection) {
        collection.find( jsonQuery, jsonProjection).sort(jsort).toArray( function(err, items) {
            res.send(items);
        });
    });
}

最后,您可能想学习 express 和 mongo 的教程,有一些很好的教程,我根据 Chris Coenraets 的出色入门者将这个答案放在一起,请参见:-

http://coenraets.org/blog/2012/10/creating-a-rest-api-using-node-js-express-and-mongodb/

  • 使用标准的 mongo 查询外壳,默认情况下您仅限于分页结果集,其中键入“it”将遍历结果。
于 2013-11-07T09:56:59.973 回答
4

请记住,投影允许我们在MongoDB查询中显式包含或排除字段。我们1用来表示我们想要包含一个字段并0表示我们希望排除该字段。请记住,该_id字段是特殊的-

  • _id默认情况下包含字段,除非我们明确排除它
  • 所有其他字段都被排除在外,直到我们明确包含它们

此外,由于我们在 中工作javascript,我们可以构建我们的项目文档和要插入到我们的集合中的文档,其方式与我们在mongoshell 中执行此操作的方式非常相似。不同的是驱动程序提供了一组我们用来交互的类和方法,MongoDBmongoshell 提供了它自己的 API。

W. rt CRUDas of MongoDB 3.2driver 和mongoshell 遵循相同的规范。您访问这些方法的方式以及它们的实现方式当然因mongoshell 而异。



var MongoClient = require('mongodb').MongoClient,
    assert = require('assert');


MongoClient.connect('mongodb://localhost:27017/crunchbase', function(err, db) {

    assert.equal(err, null);
    console.log("Successfully connected to MongoDB.");

    var query = {"category_code": "biotech"};
    var projection = {"name": 1, "category_code": 1, "_id": 0};

    var cursor = db.collection('companies').find(query);
    cursor.project(projection);

    cursor.forEach(
        function(doc) {
            console.log(doc.name + " is a " + doc.category_code + " company.");
            console.log(doc);
        },
        function(err) {
            assert.equal(err, null);
            return db.close();
        }
    );

});


驱动程序中当前的最佳实践node.js是将调用链接project到我们的cursorie上cursor.project。这个对 project 的调用为查询设置了一个字段投影。此调用不会像该foreach方法一样强制请求从数据库中检索文档。相反,它为我们维护的查询表示添加了一些额外的细节cursor。有许多游标方法,我们可以链接在一起以完全表达我们希望对MongoDB数据库执行的操作。调用db.collection是同步的。我们将使用光标上的方法在此处使用cursor字段对其进行修改。projectionproject

于 2016-08-29T18:07:51.090 回答
0

不知道我是否理解:

find({year:2013},function(err,clients){})

这将返回您该年等于 2013 年的所有客户,它返回您所有文档字段

您正在谈论的投影用于限制查询返回的字段,我的意思是:

find({year:2013},{year:1,paid:1},function(err,clients){})

这将返回一个对象数组,其中年份是 2013 年并且每个对象都有 2 个字段(付费和年份)

"{year:1,paid:1}" 对象是您的投影仪。

于 2013-10-30T17:31:57.093 回答
-1

正如@JohnnyK 在他的评论中提到的,您应该使用 MongoDB聚合框架

db.clients.aggregate([
  { $unwind: "$invoices" },
  { $match: { "invoices.year": 2013 } },
  { $group: { _id: "$_id", /* other client fields */, invoices: { $push: "$invoices" } } }
]);

首先,您展开初始invoices数组,然后只保留指定年份的发票,最后按客户字段将匹配的发票分组到数组中。

于 2013-11-01T13:36:18.230 回答