我正在尝试将CSV文件添加到我的mongodb集合(通过mongoose),同时检查我的架构的每个级别的匹配。
因此对于具有嵌套模式personSchema
的给定模式carSchema
:
repairSchema = {
date: Date,
description: String
}
carSchema = {
make: String,
model: String
}
personSchema = {
first_name: String,
last_name: String,
car: [carSchema]
}
和我mapping the CSV data to的对象:
mappingObject = {
first_name : 0,
last_name: 1,
car : {
make: 2,
model: 3,
repair: {
date: 4,
description: 5
}
}
}
检查我的集合是否匹配,然后检查每个嵌套模式以查找匹配项,或者根据需要创建整个文档。
所需流程:
我需要检查我的收藏中是否存在与first_name
和last_name
匹配的人员文档。
如果存在此类人员文档,请检查该人员文档是否包含匹配的car.make
和car.model
。
如果存在此类汽车文件,请检查该汽车文件是否包含匹配的car.repair.date
和car.repair.description
。
如果存在此类修复文档,则不执行任何操作,与现有记录完全匹配。
如果此类修理文件不存在,请将此维修推送至相应汽车和人员的维修文件。
如果这样的汽车文件不存在,请将此车推送给适当人员的汽车文件。
如果此类人员文档不存在,请创建文档。
踢球者
这个函数将在许多模式中使用,可以嵌套很多级别(当前数据库有一个模式,深度为7级)。所以它必须相当抽象。 我已经可以将数据添加到我需要的结构中作为javascript对象,所以我只需要从该对象获取所描述的 。
它也必须是同步的,因为来自CSV的多个记录可能具有相同的人,并且异步创建可能意味着同一个人被创建两次。
当前解决方案
我运行each line of the CSV,将数据映射到我的mappingObject
,然后在javascript中逐步浏览对象的每个级别,使用{{1}检查匹配的非对象键值对然后根据需要推送/创建或递归。这绝对有效,但是如此庞大的文档会很慢。
这是我的完整递归函数,它起作用:
find
是我将CSV映射到的对象与我的架构匹配。
saveObj
最初是假的。 findPrevObj
和path
最初都是topKey
。
""
是行读者对象,lr
只是移动到下一行。
lr.resume
答案 0 :(得分:1)
为了清楚起见,我会更新,但是person.find是检查是否存在具有匹配名和姓的人。如果它们存在,我会检查每辆车是否匹配 - 如果车已经存在,那么没有理由添加此记录。如果汽车不存在,我会把它推到汽车阵列中以供匹配的人使用。如果没有人匹配,我将保存整个新记录。
啊,你想要的是用upsert更新:
替换
Person.find({first_name: "adam", last_name: "snider"}).exec(function(e, d){
//matched? check {first_name: "adam", last_name: "snider", car.make: "honda", car.model: "civic"}
//no match? create this record (or push to array if this is a nested array)
});
带
Person.update(
{first_name: "adam", last_name: "snider"},
{$push: {car: {make: 'whatever', model: 'whatever2'}}},
{upsert: true}
)
如果找到匹配项,则会进入或创建此car
字段{car_make: 'whatever', car_model: 'whatever2'}
。
如果未找到匹配项,则会创建一个类似于以下内容的新文档:
{first_name: "adam", last_name: "snider", car: {car_make: 'whatever', car_model: 'whatever2'}}
这会使您的数据包往返总数减少一半。但是,为了提高效率,您可以使用orderedBulkOperation。这将导致单往返数据库。
在这里看起来像什么(在这里使用es6来简洁......不是必需的):
const bulk = Person.collection.initializeOrderedBulkOp();
lr.on('line', function(line) {
const [first_name, last_name, make, model, repair_date, repair_description] = line.split(',');
// Ensure user exists
bulk.update({first_name, last_name}, {first_name, last_name}, {upsert: true});
// Find a user with the existing make and model. This makes sure that if the car IS there, it matches the proper document structure
bulk.update({first_name, last_name, 'car.make': make, 'car.model': model}, {$set: {'car.$.repair.date': repair_date, 'car.$.repair.description': repair_description}});
// Now, if the car wasn't there, let's add it to the set. This will not push if we just updated because it should match exactly now.
bulk.update({first_name, last_name}, {$addToSet: {car: {make, model, repair: {date: repair_date, description: repair_description}}}})
});