如何管理Mongodb中的子列表?

时间:2014-04-09 18:44:15

标签: mongodb mongodb-php

我有不同类型的数据,很难用关系数据库建模和扩展(例如,产品类型)

我对使用Mongodb解决这个问题感兴趣。

我在mongodb的网站上引用了这些文档:

http://docs.mongodb.org/manual/tutorial/model-referenced-one-to-many-relationships-between-documents/

对于我正在存储的数据类型,我还需要维护此特定产品可用的ID的关系列表(例如,商店位置ID)。

在他们关于"与嵌入式文档的一对多关系"的示例中,他们有以下内容:

{
   name: "O'Reilly Media",
   founded: 1980,
   location: "CA",
   books: [12346789, 234567890, ...]
}

我目前正在使用电子表格导入数据,并希望使用batchInsert。

为避免重复,我认为:

1)我需要对ID做一个保证索引,并忽略插入错误? 2)我是否需要遍历所有ID以在书籍中插入新的相关ID?

1 个答案:

答案 0 :(得分:0)

您的问题可能会更好地定义,但请考虑您在电子表格或其他来源中有行以某种方式进行非规范化的情况。因此,在JSON表示中,行将是这样的:

{
    "publisher": "O'Reilly Media",   
    "founded": 1980,
    "location": "CA",
    "book": 12346789
},
{
    "publisher": "O'Reilly Media",
    "founded": 1980,
    "location": "CA",
    "book": 234567890
}

因此,为了将这些行结果放入您想要的结构中,一种方法是使用"upsert"方法的.update()功能:

所以假设你有一些循环输入值的方法,并且它们被识别为某种结构,那么类似于这样的类似:

books.forEach(function(book) {

    db.publishers.update(
        { 
            "name": book.publisher
        },
        {
            "$setOnInsert": {
                "founded": book.founded,
                "location": book.location,
            },
            "$addToSet": { "books": book.book }
        },
        { "upsert": true }
    );

})

这基本上简化了代码,以便MongoDB为您完成所有数据收集工作。那么" name"发布者被认为是唯一的,声明所做的是首先在集合中搜索与给定的查询条件匹配的文档,作为" name"。

如果找不到该文档,则插入新文档。因此,数据库或驱动程序将负责为此文档和您的"条件"创建新的_id值。也会自动插入新文档,因为它是一个应该存在的隐含值。

$setOnInsert运算符的用法是仅在创建新文档时设置这些字段。最后一部分使用$addToSet以便"推送"尚未在"书籍中找到的书籍价值"数组(或集)。

分离的原因是当实际发现文档存在于指定的"发布者"名称。在这种情况下,$setOnInsert下的所有字段都将被忽略,因为它们应该已经在文档中。因此,只处理$addToSet操作并将其发送到服务器,以便将新条目添加到" books"数组(集)以及它尚不存在的位置。

与在发送新的插入操作之前聚合代码中的新记录相比,这将是简化的逻辑。然而,它不是很好的批次"就像你仍在为每一行对服务器执行某些操作一样。

这已在MongoDB 2.6及更高版本中修复,因为现在可以执行"batch" updates。所以用类似的模拟:

var batch = [];

books.forEach(function(book) {

    batch.push({
        "q": { "name": book.publisher },
        "u": {
            "$setOnInsert": {
                "founded": book.founded,
                "location": book.location,
            },
            "$addToSet": { "books": book.book }
        },
        "upsert": true
    });

    if ( ( batch.length % 500 ) == 0 ) {
        db.runCommand( "update", "updates": batch );
        batch = [];
    }
});

db.runCommand( "update", "updates": batch );

那么在将所有构造的更新语句设置为对服务器的单个调用中的操作是什么,其中批处理中发送了合理的操作大小,在这种情况下,每处理500个项目一次。实际限制是BSON文档最大值为16MB,因此可以根据您的数据进行更改。

如果您的MongoDB版本低于2.6,那么您可以使用第一个表单或使用现有批量插入功能执行与第二个表单类似的操作。但是,如果您选择插入,则需要在代码中进行所有预聚合工作。

所有这些方法当然都支持PHP驱动程序,因此只需根据您的实际代码和您想要的课程进行调整即可。