【问题标题】:mongodb - capped collections with nodejsmongodb - 使用 nodejs 的封顶集合
【发布时间】:2015-04-25 04:29:47
【问题描述】:

我正在尝试使用 Node.js(使用本机 MongoDB 驱动程序)在 MongoDB 中设置和更新一些上限集合。 我的目标是,在运行 app.js 时,将文档插入到上限集合中,并更新上限集合中的现有文档。这两个都在setInterval() 上运行,所以每隔几秒钟。

我的问题:

  1. 如果集合尚不存在,我想创建一个集合,但如果存在,我想在其中插入一个文档。检查这个的正确方法是什么?
  2. 对于有上限的集合,我是否应该在向其中插入任何内容之前先显式创建它们?通常我相信你可以在不先明确创建它们的情况下将它们插入集合中,但在这种情况下,我需要确保它们被封顶。一旦存在上限集合,我就知道如何将新文档插入其中,问题是我需要一些方法来处理第一次使用的应用程序(在新服务器上),其中集合尚不存在,我想要使用节点进行此创建,而不必跳转到 mongo cli。
  3. 这里的诀窍是集合需要设置上限,所以我可以执行以下操作:db.createCollection("collectionName", { capped : true, size : 100000, max : 5000 } )。这将为我创建上限集合,但每次我调用它时它都会调用 createCollection() 而不是更新或插入 - 如果我调用 createCollection(),一旦集合已经存在,它会完全覆盖现有集合吗?李>
  4. 另一种方法是将集合转换为具有上限的集合:db.runCommand({"convertToCapped": "collectionName", size: 100000, max : 5000 });。这样做的问题是节点没有将runCommand() 视为有效函数并且它出错。还有什么我打算打电话来让它工作的吗?它在 mongo cli 中有效,但在节点中无效
  5. 您使用什么类型的查询来查找集合中的第一个文档?同样,在 mongo cli 中,我可以使用 db.collections.find() 进行一些查询,但在节点中它指出 find() 不是有效函数
  6. 如何使用collection.update() 向现有文档添加一些新字段?假设文档是一些简单的对象,例如{key1: "value", key2: "value"},但我有一个包含{key3: "value"} 的对象。当前文档中不存在密钥 3,如何将其添加到当前存在的内容中?这与上面的 #4 有点相关,因为我不确定应该将什么作为查询参数传入,因为 find() 似乎与节点不兼容。

【问题讨论】:

    标签: javascript node.js mongodb native capped-collections


    【解决方案1】:

    关于您的问题 1 - 4 关于上限集合并自动创建它们,有几种方法可以做到这一点。一方面,您可以运行一个脚本来初始化您的数据库,这样当您第一次运行它时,它就可以为您的客户提供可用的上限集合。另一方面,您可以在插入文档之前检查给定集合中是否有任何文档。如果有,您只需插入您的文档,如果没有,您创建 capped 集合,然后插入文档作为对该函数的回调。它会像这样工作:

    var host = "localhost",
    port = 27017,
    dbName = "so";
    
    var MongoClient = require('mongodb').MongoClient, Server = require('mongodb').Server;
    var mongoclient = new MongoClient(new Server(host, port));
    var db = mongoclient.db(dbName);
    
    db.open(function(err, db) {
    
        if(err) throw err;
    
        // Capped collection.
        var capped = db.collection('capped');
    
        // Document to be inserted.
        var document =  { "foo": 1, "bar": 1 }
    
        capped.find().count(function(err, count) {
    
            if(err) throw err;
    
            if (count === 0) {          
                console.log("Creating collection...");
                db.createCollection("capped",
                                    { "capped": true,
                                      "size": 100000,
                                      "max": 5000 },
                                    function(err, collection) {
                    if(err) throw err;              
    
                    // Insert a document here.
                    console.log("Inserting document...");
                    collection.insert(document, function(err, result) {
                        if (err) throw err;                 
                    });
                });
    
            } else {
    
                // Insert your document here without creating collection.
                console.log("Inserting document without creating collection...");
                capped.insert(document, function(err, result) {
                    if (err) throw err;             
                });
            }
    
        });
    });
    

    关于问题 5,您可以使用findOne() 在集合中查找文档,但这不一定是第一个或最后一个。如果你想保证第一个或最后一个,你可以运行一个find(),其中sort()limit() 为1。按_id 升序排序应该会给你第一个文档。更多信息here

    // Sort 1 for ascending, -1 for descending.
    capped.find().sort([["_id", 1]]).limit(1).nextObject(function(err, item) {
        console.log(item);
    });
    

    最后,对于问题 6,您只需将 $set 运算符与 update() 方法一起使用。更多信息here

    capped.update({ "foo": 1 }, { "$set": { "bar": 2 } }, {}, function(err, result) {
        console.log(result);
    });
    

    请注意,您只能为有上限的集合更新文档,因此您不能插入您提到的额外字段。您可能需要了解here 列举的其他限制。

    [编辑:在最后一个文档中添加更新嵌套字段。]

    如果您想更新第一个或最后一个文档中的嵌套字段(分别在排序中使用 1 或 -1),您可以获取该文档,提取 _id,然后对该文档执行原子更新.像这样的:

    capped.find().sort([["_id", -1]]).limit(1).nextObject(function(err, item) {       
        if(err) throw err;
        capped.update({ "_id": item._id },
                  { "$set": { "timeCollected": 15, "publicIP.ip" : "127.0.0.1" }},
                  function(err, result) {
    
            if(err) throw err;
            console.log(result);    
        });
    });  
    

    请注意,即使在上限集合中更新文档中存在的字段时,您也需要确保新值适合为文档分配的空间。因此,例如,将字符串值从 "1" 更新为 "127.0.0.1" 不一定有效。

    【讨论】:

    • 谢谢。我在这里尝试了一些想法,到目前为止它们都在起作用。关于文档更新:我真正想做的是更新集合中的第一个文档。那么您对 ​​{"foo": 1} 的查询,我该如何替换它以便查询返回第一个文档?
    • 我遇到了一个奇怪的问题:我有一个看起来像 dataObject = {"timeCollected": 3432547, "publicIP": {"ip": "xx.xxx.xx.xx"} (...plus many others) } 的对象。然后我将一些值从那里提取到一个新对象中:systemInfo = {"timeCollected": dataObject.timeCollected, "publicIP": dataObject.publicIP.ip,}。我想更新现有文档中的 timeCollected 和 publicIP 字段(最初在文档中这两个字段都设置为 0)。
    • 我使用 collection.update(query, {"$set": systemInfo}, function(err, result) {} 之类的东西,但两个字段都没有更新。奇怪的是,如果我只尝试更新 timeCollected 那么它工作正常,但尝试更新两者都行不通,也不会自行更新 publicIP
    • 尽管如果我将对象更改为systemInfo = {"timeCollected": 55, "publicIP": 5},那么两个字段都会更新。所以它似乎与从嵌套对象中提取值有关?
    • 我的第二篇文章有一个错误,systemInfo 对象末尾的, 只是一个错字
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-17
    相关资源
    最近更新 更多