CSV到Mongo使用mongoose模式

时间:2015-11-13 16:01:54

标签: node.js mongodb csv mongoose schema

我正在尝试将CS​​V文件添加到我的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_namelast_name匹配的人员文档。

如果存在此类人员文档,请检查该人员文档是否包含匹配的car.makecar.model

如果存在此类汽车文件,请检查该汽车文件是否包含匹配的car.repair.datecar.repair.description

如果存在此类修复文档,则不执行任何操作,与现有记录完全匹配。

如果此类修理文件不存在,请将此维修推送至相应汽车和人员的维修文件。

如果这样的汽车文件不存在,请将此车推送给适当人员的汽车文件。

如果此类人员文档不存在,请创建文档。

踢球者

这个函数将在许多模式中使用,可以嵌套很多级别(当前数据库有一个模式,深度为7级)。所以它必须相当抽象。 我已经可以将数据添加到我需要的结构中作为javascript对象所以我只需要从该对象获取所描述的

它也必须是同步的,因为来自CSV的多个记录可能具有相同的人,并且异步创建可能意味着同一个人被创建两次。

当前解决方案

我运行each line of the CSV,将数据映射到我的mappingObject,然后在javascript中逐步浏览对象的每个级别,使用{{1}检查匹配的非对象键值对然后根据需要推送/创建或递归。这绝对有效,但是如此庞大的文档会很慢。

这是我的完整递归函数,它起作用:

find是我将CSV映射到的对象与我的架构匹配。

saveObj最初是假的。 findPrevObjpath最初都是topKey

""是行读者对象,lr只是移动到下一行。

lr.resume

1 个答案:

答案 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}}}})
});