gpt4 book ai didi

mongodb - 如何在不使用封顶集合的情况下在MongoDB中存储一组有序文档

转载 作者:IT老高 更新时间:2023-10-28 13:36:18 25 4
gpt4 key购买 nike

在顺序很重要的MongoDB中存储一组文档的好方法是什么?我需要轻松地将文档插入任意位置,并可能在以后重新排序。

我可以为每个项目分配一个递增的数字并以此排序,或者我可以按_id进行排序,但是我不知道如何在另一个文档之间插入另一个文档。假设我想在sequence5的元素和sequence6的元素之间插入一些内容?

我的第一个猜测是增加以下所有元素的sequence,以便使用诸如db.items.update({"sequence":{$gte:6}}, {$inc:{"sequence":1}})之类的查询为新元素留出空间。我对数据库管理的有限了解告诉我,这样的查询会很慢,并且通常是一个坏主意,但我很高兴得到纠正。

我想我可以将新元素的sequence设置为5.5,但是我认为这会很快变得困惑。 (再次,如果我错了,请纠正我。)

我可以使用有上限的集合,该集合有保证的顺序,但是如果我需要增加集合的数量,那么我会遇到问题。 (再次,我可能也错了。)

我可以让每个文档都包含对下一个文档的引用,但这将需要查询列表中的每个项目。 (您将获得一个项目,将其插入结果数组,并基于当前项目的next字段获得另一个项目。)除了明显的性能问题之外,我也无法将经过排序的mongo游标传递给我的{#each}空格键块表达式,并随着数据库的变化而实时更新。 (我正在使用Meteor全栈javascript框架。)

我知道一切都有其优点和缺点,我可能只需要使用上面列出的选项之一,但是我想知道是否有更好的方法来做事情。

最佳答案

根据您的需求,一种方法可能是设计模式,以使每个文档都能够容纳一个以上的文档,并且其本身就可以作为一个有顶盖的容器。

{
"_id":Number,
"doc":Array
}

集合中的每个文档将充当加盖的容器,并且这些文档将作为数组存储在 doc字段中。 doc字段是一个数组,将保持插入顺序。
您可以将文档数限制为 n。因此,每个容器文档的 _id字段将增加 n,指示容器文档可以容纳的文档数。

通过执行这些操作,您 避免extra fields添加到文档 extra indicesunnecessary sorts中。

插入第一条记录

即当集合为空时。
var record = {"name" : "first"};
db.col.insert({"_id":0,"doc":[record]});

插入后续记录
  • 标识最后一个容器文档的_id和的number它拥有的文件。
  • 如果它持有的文档数少于n,则更新
    包含新文档的容器文档,否则创建一个新容器
    文档。

  • 假设每个 container document最多可以容纳 5文档,我们想插入一个新文档。
    var record = {"name" : "newlyAdded"};

    // using aggregation, get the _id of the last inserted container, and the
    // number of record it currently holds.
    db.col.aggregate( [ {
    $group : {
    "_id" : null,
    "max" : {
    $max : "$_id"
    },
    "lastDocSize" : {
    $last : "$doc"
    }
    }
    }, {
    $project : {
    "currentMaxId" : "$max",
    "capSize" : {
    $size : "$lastDocSize"
    },
    "_id" : 0
    }
    // once obtained, check if you need to update the last container or
    // create a new container and insert the document in it.
    } ]).forEach( function(check) {
    if (check.capSize < 5) {
    print("updating");
    // UPDATE
    db.col.update( {
    "_id" : check.currentMaxId
    }, {
    $push : {
    "doc" : record
    }
    });
    } else {
    print("inserting");
    //insert
    db.col.insert( {
    "_id" : check.currentMaxId + 5,
    "doc" : [ record ]
    });
    }
    })

    请注意, aggregation在服务器端运行,非常高效,还请注意, aggregation将返回 文档而不是 previous to 2.6版本中的 游标。因此,您需要修改以上代码以仅从单个文档中进行选择,而不是迭代游标。

    在文档之间插入新文档

    现在,如果您想在文档 12之间插入一个新文档,我们知道该文档应放入带有 _id=0的容器内,并应放置在该容器的 second数组中的 doc位置。

    因此,我们利用 $each$position运算符将其插入特定位置。
    var record = {"name" : "insertInMiddle"};

    db.col.update(
    {
    "_id" : 0
    }, {
    $push : {
    "doc" : {
    $each : [record],
    $position : 1
    }
    }
    }
    );

    处理流量

    现在,我们需要照顾每个 overflowing中的文件 container,比如说我们在之间插入一个新文件 _id=0到容器中。如果容器已经有 5文档,则需要 move the last document to the next container并这样做,直到所有容器都在其容量范围内容纳文档为止,如果需要,最后需要创建一个容器来容纳溢出的文档。

    这个复杂的操作 应该在服务器端上完成。为了解决这个问题,我们可以创建一个脚本,例如下面的脚本,并用mongodb对其进行 register编码。
    db.system.js.save( {
    "_id" : "handleOverFlow",
    "value" : function handleOverFlow(id) {
    var currDocArr = db.col.find( {
    "_id" : id
    })[0].doc;
    print(currDocArr);
    var count = currDocArr.length;
    var nextColId = id + 5;
    // check if the collection size has exceeded
    if (count <= 5)
    return;
    else {
    // need to take the last doc and push it to the next capped
    // container's array
    print("updating collection: " + id);
    var record = currDocArr.splice(currDocArr.length - 1, 1);
    // update the next collection
    db.col.update( {
    "_id" : nextColId
    }, {
    $push : {
    "doc" : {
    $each : record,
    $position : 0
    }
    }
    });
    // remove from original collection
    db.col.update( {
    "_id" : id
    }, {
    "doc" : currDocArr
    });
    // check overflow for the subsequent containers, recursively.
    handleOverFlow(nextColId);
    }
    }

    因此,对于 after every insertion in between,我们可以通过传递容器ID function来调用此 handleOverFlow(containerId)

    按顺序获取所有记录

    只需在 $unwind中使用 aggregate pipeline运算符即可。
    db.col.aggregate([{$unwind:"$doc"},{$project:{"_id":0,"doc":1}}]);

    重新订购文件

    您可以使用“_id”字段将每个文档存储在加盖的容器中:
    .."doc":[{"_id":0,","name":"xyz",...}..]..

    获取所需的带帽容器的“doc”数组
    重新排序商品。
    var docArray = db.col.find({"_id":0})[0];

    更新其ID,以便在排序后更改项目的顺序。

    根据其_id对数组进行排序。
    docArray.sort( function(a, b) {
    return a._id - b._id;
    });

    使用新的doc数组更新加盖的容器。

    但话又说回来,一切都归结为哪种方法可行并最适合您的要求。

    提出您的问题:

    What's a good way to store a set of documents in MongoDB where order is important?I need to easily insert documents at an arbitrary position and possibly reorder them later.



    文档为数组。

    Say I want to insert something between an element with a sequence of 5 and an element with a sequence of 6?



    如我的答案所述,在 $each函数中使用 $positiondb.collection.update()运算符。

    My limited understanding of Database Administration tells me that a query like that would be slow and generally a bad idea, but I'm happy to be corrected.



    是的。除非集合中的数据很少,否则它将影响性能。

    I could use a capped collection, which has a guaranteed order, but then I'd run into issues if I needed to grow the collection. (Yet again, I might be wrong about that one too.)



    是的。使用上限集合,您可能会丢失数据。

    关于mongodb - 如何在不使用封顶集合的情况下在MongoDB中存储一组有序文档,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26220879/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com