如何在MongoDB中保留订单?

时间:2013-12-17 20:11:06

标签: mongodb

在我的MongoDB文档中,我有这样的对象

[_id] => MongoId Object (
    [$id] => 52a46b44aabacb5c218b4567
)
[results] => Array (
    [http://google.com] => Array (
        [position] => 1
        [data] => 42672
    )
    [http://bing.com] => Array (
        [position] => 2
        [data] => 9423
    )
    [http://yandex.com] => Array (
        [position] => 3
        [data] => 5513
    )
)

我想将“bing.com”中的数据参数从9423更改为例如300.此外,我必须保持网站的顺序。它必须看起来像这样

[_id] => MongoId Object (
    [$id] => 52a46b44aabacb5c218b4567
)
[results] => Array (
    [http://google.com] => Array (
        [position] => 1
        [data] => 42672
    )
    [http://bing.com] => Array (
        [position] => 2
        [data] => 300
    )
    [http://yandex.com] => Array (
        [position] => 3
        [data] => 5513
    )
)

这在Mongo中是否可以实现?

3 个答案:

答案 0 :(得分:1)

为了清楚起见,我在下面使用mongo shell包含了一些示例,但PHP等效项应该很容易解决。

我注意到您最初将您的网站列表建模为嵌入文档,但目前无法保证嵌入文档中字段的顺序保留,因此您应该使用数组。

此外,您不能在MongoDB中使用带有嵌入点(。)的字段名称,因此您不应计划将URL存储为字段名称(请参阅:Field name restrictions)。

为了在数组中查找元素,您需要按值(而不是字段名称)进行搜索,这样您的模式应该更像:

{
    _id: ObjectId("52a46b44aabacb5c218b4567"),
    results: [
        {
            site: 'http://google.com',
            position: 1,
            data: 42762
        },
        {
            site: 'http://bing.com',
            position: 2,
            data: 9423
        },
        {
            site: 'http://yandex.com',
            position: 3,
            data: 5513
        }
    ]
}

假设数组site元素是唯一的,您可以使用positional operator $来查找和更新匹配的嵌入式文档。

例如,要执行“bing.com”data值的更新:

db.sites.update(
    // Match criteria
    {
        _id:ObjectId("52a46b44aabacb5c218b4567"),
        'results.site':'http://bing.com'
    },
    // Update
    { $set: {
        'results.$.data': 300 }
    }
)

在MongoDB 2.4+中,您可以选择pushing to a sorted array,这也是在添加新条目时按排序顺序维护数组的有用方法。

值得注意的是,如果您计划在阵列中存储许多(即数千个)项目,则由于文档增长和更新大型阵列的复杂性,这会造成严重的性能损失。

答案 1 :(得分:1)

自MongoDB v2.5.2(2.6版本)起,字段issue的重新排序已得到修复。说过一种可以完全避免问题的方法是将结果作为数组而不是(子)文档。另请注意,您不应使用“。”作为关键名称的一部分。 使用2.4,使用以下内容,您将看到在_id = 1(子文档)的情况下有重新排序,但在_id = 2(数组)的情况下则没有。

$document = array("_id" => 1, "results" => array('http://google.com' => array('position' => 1, 'data' => 42672),
  'http://bing.com' => array('position' => 2, 'data' => 9423),
  'http://yandex.com' => array('position' => 3, 'data' => 5513)));
$coll->insert($document);
$document = array("_id" => 2, "results" => array(array('site' => 'http://google.com', 'data' => 42672),
  array('site' => 'http://bing.com', 'data' => 9423),
  array('site' => 'http://yandex.com', 'data'  => 5513)));
$coll->insert($document);

$coll->update(array("_id" => 1),     array('$set'=>array("results.http://bing.com.data"=>300)));
$coll->update(array("_id" => 2, 'results.site' => 'http://bing.com'), array('$set'=>array('results.$.data'=>300)));

答案 2 :(得分:0)

我很确定(与其他所有DBMS一样)您不能并且不应该依赖记录订单。

相反,我会建议您添加index(在position上,即db.people.ensureIndex( { position: 1 } ))并查询按该字段排序的记录,i。 e。:db.collection.find().sort( { position: 1 } )