MongoDB - 使用Node.js创建固定集合

6
我正在使用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 });。问题在于node不认为runCommand()是一个有效的函数,并且会出现错误。我是否需要调用其他内容才能使其正常工作?它在mongo cli中可以工作,但在节点中无法正常工作。
5.您要使用什么类型的查询来查找集合中的第一个文档?同样,在mongo cli中,我可以使用db.collections.find()与某个查询,但在节点中,它指出find()不是有效的函数。
6.如何使用collection.update()向现有文档添加一些新字段?假设文档是一些简单对象,例如{key1: "value", key2: "value"},但我有一个包含{key3: "value"}的对象。键3不存在于当前文档中,我应该如何将其添加到当前存在的文档中?这与上面的#4有些相关,因为我不确定在query参数中传递什么,因为find()似乎不能很好地与node配合使用。
1个回答

3

关于有关限制集合和自动创建它们的问题1-4,有几种方法可以实现。一方面,您可以运行一个脚本来初始化您的数据库,以便在第一次运行时为客户端提供可用的限制集合。另一方面,您可以检查给定集合中是否有任何文档,然后再插入文档。如果有文档,只需插入您的文档,如果没有,则创建被限制的集合,然后将文档作为回调函数插入其中。它的工作原理如下:

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()在集合中查找文档,但这不一定是第一个或最后一个。如果您想保证第一个或最后一个,可以运行带有sort()limit()为1的find()。按_id升序排序应该会给您第一个文档。更多信息在这里

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

最后对于问题6,你只需要使用$set操作符和update()方法即可。更多信息请参见此处

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

请注意,只有在固定大小的集合中才能就地更新文档,因此您无法执行您提到的插入额外字段操作。 这里列举了其他限制,您可能想要了解一下。
[编辑:在最后一个文档中更新嵌套字段]
如果您想要更新第一个或最后一个文档中的嵌套字段(分别在排序中使用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},我该如何替换它,以便查询返回第一个文档? - Simon
我遇到了一个看起来很奇怪的问题:我有一个对象,看起来像这样 dataObject = {"timeCollected": 3432547, "publicIP": {"ip": "xx.xxx.xx.xx"} (...加上许多其他内容) }。然后我从中提取一些值到一个新对象中:systemInfo = {"timeCollected": dataObject.timeCollected, "publicIP": dataObject.publicIP.ip,}。我想要更新现有文档中的timeCollected和publicIP字段(这两个字段最初在文档中都设置为0)。 - Simon
我使用类似于collection.update(query, {"$set": systemInfo}, function(err, result) {}的东西,但是没有一个字段更新。奇怪的是,如果我只尝试更新timeCollected,那么它就可以正常工作,但是尝试同时更新两个字段或者仅更新publicIP都不起作用。 - Simon
如果我将对象更改为systemInfo = {"timeCollected": 55, "publicIP": 5},那么两个字段都会更新。因此,这似乎与从嵌套对象中提取值有关? - Simon
我的第二篇帖子中出现了一个错误,systemInfo对象末尾的逗号只是一个打字错误。 - Simon
@Nem,我在答案中包含了与此情况相关的内容。如果有帮助,请告诉我。 - Juan Carlos Farah

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接