您的问题可能定义得更好一些,但让我们考虑一下电子表格或其他来源中的行都以某种方式去规范化的情况。因此,在 JSON 表示中,行将是这样的:
{
"publisher": "O'Reilly Media",
"founded": 1980,
"location": "CA",
"book": 12346789
},
{
"publisher": "O'Reilly Media",
"founded": 1980,
"location": "CA",
"book": 234567890
}
因此,为了将这些行结果放入您想要的结构中,一种方法是使用.update() 方法的"upsert" 功能:
因此,假设您有某种循环输入值的方法,并且它们用某种结构标识,那么类似的情况如下:
books.forEach(function(book) {
db.publishers.update(
{
"name": book.publisher
},
{
"$setOnInsert": {
"founded": book.founded,
"location": book.location,
},
"$addToSet": { "books": book.book }
},
{ "upsert": true }
);
})
这基本上简化了代码,以便 MongoDB 为您完成所有数据收集工作。因此,当发布者的“名称”被认为是唯一的时,该语句首先在集合中搜索与给定查询条件匹配的文档,作为“名称”。
如果找不到该文档,则插入一个新文档。因此,数据库或驱动程序将负责为此文档创建新的 _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 驱动程序当然支持所有方法,因此只需根据您的实际代码和您想学习的课程进行调整即可。