【问题标题】:MongoDB query criterias and projectionsMongoDB 查询条件和预测
【发布时间】:2013-10-30 14:15:20
【问题描述】:

我正在使用 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}
]

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

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

【问题讨论】:

  • 看看使用aggregate 而不是find$unwind 运算符。
  • 您的查询是什么样的?

标签: node.js mongodb express mongoskin


【解决方案1】:

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

.findOne(query) 会将结果限制为 1,或者 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 查询 shell,默认情况下您仅限于分页结果集,其中键入“it”将遍历结果。

【讨论】:

    【解决方案2】:

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

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

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

    W。河。吨。 CRUDMongoDB 3.2 开始,驱动程序和 mongo shell 遵循相同的规范。当然,您访问这些方法的方式以及它们的实现方式各不相同,与 mongo shell 不同。

    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 的调用链接到我们的cursor 上,即cursor.project。这个对 project 的调用为查询设置了一个字段投影。此调用不会强制请求从数据库中检索文档,foreach 方法也是如此。相反,它为我们的cursor 维护的查询表示添加了一些额外的细节。有许多游标方法,我们可以链接在一起以完全表达我们希望对MongoDB 数据库执行的操作。对db.collection 的调用是同步的。我们将在此处使用光标上的project 方法修改cursor 字段projection

    【讨论】:

      【解决方案3】:

      不确定我是否理解:

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

      这将返回你所有的客户那一年等于 2013,它返回你所有的文档字段

      您所说的投影用于限制查询返回的字段,我的意思是:

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

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

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

      【讨论】:

        【解决方案4】:

        正如@JohnnyK 在他的评论中提到的,你应该使用 MongoDB aggregation framework

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

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

        【讨论】:

          猜你喜欢
          • 2015-12-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-02-02
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多