【发布时间】:2016-02-15 06:42:27
【问题描述】:
我正在尝试将 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 中逐步遍历对象的每个级别,使用 find 检查非对象键值对是否匹配,然后推送/创建或酌情递归。这绝对有效,但是对于如此大的文档来说速度非常慢。
这是我的完整递归函数,它有效:
saveObj 是我已将 CSV 映射到与我的架构匹配的对象。
findPrevObj 最初为假。 path 和 topKey 最初都是 ""。
lr 是行阅读器对象,lr.resume 只是移动到下一行。
var findOrSave = function(saveObj, findPrevObj, path, topKey){
//the object used to search the collection
var findObj = {};
//if this is a nested schema, we need the previous schema search to match as well
if (findPrevObj){
for (var key in findPrevObj){
findObj[key] = findPrevObj[key];
}
}
//go through all the saveObj, compiling the findObj from string fields
for (var key in saveObj){
if (saveObj.hasOwnProperty(key) && typeof saveObj[key] === "string"){
findObj[path+key] = saveObj[key]
}
}
//search the DB for this record
ThisCollection.find(findObj).exec(function(e, doc){
//this level at least exists
if (doc.length){
//go through all the deeper levels in our saveObj
for (var key in saveObj){
var i = 0;
if (saveObj.hasOwnProperty(key) && typeof saveObj[key] === "string"){
i += 1;
findOrSave(saveObj[key], findObj, path+key+".", path+key);
}
//if there were no deeper levels (basically, full record exists)
if (!i){
lr.resume();
}
}
//this level doesn't exist, add new record or push to array
} else {
if (findPrevObj){
var toPush = {};
toPush[topKey] = saveObj;
ThisCollection.findOneAndUpdate(
findPrevObj,
{$push: toPush},
{safe: true, upsert: true},
function(err, doc) {
lr.resume();
}
)
} else {
// console.log("\r\rTrying to save: \r", saveObj, "\r\r\r");
ThisCollection.create(saveObj, function(e, doc){
lr.resume();
});
}
}
});
}
【问题讨论】:
-
你能详细说明你到底想在这里做什么吗?我对第一部分的理解是,您有一个 csv,其中包含格式为
first_name,last_name,car_make,car_model的列,并且您希望遍历创建一个人的每一行。如果是这样的话,我不明白你为什么需要这样做Person.find...这里有某种独特的约束吗? -
我认为你需要在“我目前有这个工作”之后重写所有内容,目前还不清楚你的问题是什么......另外,你的数据结构能更具体一点吗?这些嵌套的关卡是什么样子的?
-
使用这个模块npmjs.com/package/csvtojson将所有数据转换成json,然后根据schema重构你的数据?
-
@jtmarmon 为了清楚起见,我会更新,但 person.find 是检查是否存在具有匹配名字和姓氏的人。如果它们确实存在,我会检查每辆车是否匹配 - 如果该车已经存在,则没有理由添加此记录。如果汽车不存在,我将其推送到匹配人的汽车阵列。如果没有人匹配,我会保存整个新记录。
-
@aishwatsingh 我尝试了该模块,它非常适合解析 csv 文件并将数据转换为我想要的结构,但这不是问题。我无法让 mongo/mongoose 检查部分匹配的现有数据(例如,匹配人,然后如果匹配则查找汽车,否则创建新记录。)它每次都会创建一个全新的记录。
标签: node.js mongodb csv mongoose schema