我要实现的目标:我要创建一辆必须与经销商进行正确映射的汽车,然后将其存储在汽车的列表/阵列中我的公司文档出现在myKaarma数据库的 companies集合中。
我面临的问题:所有逻辑都是正确的,但是即使我正在使用回调,问题也是由于异步性引起的。 我知道这个问题,但不知道如何解决。
让我解释一下问题所在:
我的companies
模型使用猫鼬:
// jshint node :true
"use strict";
const MONGOOSE = require("mongoose"),
DB = MONGOOSE.connection;
let companySchema = MONGOOSE.Schema({
company_name: {
type: String, required: true
},
company_location: {
type: String, require: true
},
cars: [{
model: {
type: String,required: true
},
year: {
type: Number, required: true
},
PriceInINR: {
type: Number, required: true
},
trim: {
type: String, required: true
},
engine: {
type: String, required: true
},
body: {
type: String, required: true
},
color: {
type: String, required: true
},
transmission_type: {
type: String, required: true
},
dealer_id: {
type: String, required: true
}
}]
});
let collection_name = "companies";
let CompanyModel = MONGOOSE.model(collection_name, companySchema);
createAscendingIndex_on_company_name(DB);
module.exports = CompanyModel;
// indexing at schema level --> using node js
function createAscendingIndex_on_company_name(DB, callback) {
let collection = DB.collection(collection_name);
// ? Create the index
collection.createIndex({
company_name: 1, // specifies : indexing type is ascending indexing
}, {
unique: true
}, function (err, result) {
if (err) {
console.log("error while setting up indexing on companies collection");
}
console.log("index created ", result, "<<<<<<<<", collection_name, " collection");
// callback("result");
});
}
//? NOTE : Creating indexes in MongoDB is an idempotent operation. So running db.names.createIndex({name:1}) would create the index only if it didn't already exist.
您会注意到我已经索引了company_name
并将其设为唯一,因此没有重复的条目这是问题
在我的代码中,当我执行以下操作时:// ? check if the company exists : and if not then create one
,我遇到的问题是,由于nodejs异步且非常快:[so suppose I have 5 car records]
,所以所有五辆车实际上都进入了我检查的代码中:
CompanyModel.find({
company_name: company_name
}, (err, companies) => {.....}
速度如此之快,以至于它们都同时运行,因此 company文档中现在当然不存在任何此类公司,因此它们都通过了if条件< / p>
if (companies.length === 0) {...});
因此,现在在我的记录中,有3辆同公司的汽车几乎都同时进入,并且都同时又通过了这些条件,但是一旦它们通过上述条件,我便要求Mongo创建公司文件
let company = new CompanyModel({
company_name: company_name,
company_location: company_location,
cars: [car]
});
company.save((err) => {...}
但是现在,所有3条记录都在这里以创建新的公司对象并添加到集合中。但是在这里,一旦其中一个创建了文档并将其添加到集合中,与此同时,其他两个也创建了它们的对象,但是由于已经创建并添加了一个对象,因此Mongo在这里抛出了唯一的异常。>
我想发生的事情是,当我们发现一个重复的对象时,则应该将具有相同公司的新车推入公司文档具有其字段{{1}的阵列中}
注意:这种情况仅在以下情况下出现:该公司不存在于集合中,但是如果该公司已经存在,那么我的代码运行正常,它将成功地将所有汽车推入相应公司的cars
字段。
这是执行我想要的功能的功能:
cars
输出:
function map_and_save_cars_in_garage() {
let carList = require("./test.json");
let totalCar = carList.length;
console.log(carList);
carList.forEach((carRecord, index) => {
let company_name = carRecord.make.toLowerCase();
let company_location = "USA";
// build a car
let car = {
model: carRecord.model,
year: carRecord.year,
PriceInINR: carRecord.priceInr,
trim: carRecord.trim,
engine: carRecord.engine,
body: carRecord.body,
color: carRecord.color,
transmission_type: carRecord.transmission,
dealer_id: undefined, // --> just for now
};
// ? search for the correct dealer --> for mapping
let dealer_email = "bitBattle_2018_" + carRecord.DealerID + "_@myKarmaa.com";
DealerModel.find({
email: dealer_email
}, (err, dealer) => {
if (err) {
console.log("Error : dealer not found for this car");
throw new Error(err);
}
car.dealer_id = dealer[0]._id; // ? update the dealer_id
// ? check if the company exists : and if not then create one
CompanyModel.find({
company_name: company_name
}, (err, companies) => {
if (err) {
console.log("Error : while finding the compay");
throw new Error(err);
}
console.log(company_name, companies);
if (companies.length === 0) {
console.log("No such Company car exists in the garrage --> creating one");
let company = new CompanyModel({
company_name: company_name,
company_location: company_location,
cars: [car]
});
company.save((err) => {
if (err) {
console.log("Error : while adding company ");
throw new Error(err);
}
console.log(index, "<<<<<<<< INDEX ", totalCar);
if (index === totalCar - 1) {
console.log("done");
res.send("build complete");
// build_complete();
}
});
} else {
console.log("Company already exists in garage : add this car with all other cars of this company");
let company = companies[0]; // ? as its sure that they are unique
let query = {
_id: company._id
};
let updat_command = {
$push: {
cars: car
}
};
CompanyModel.updateOne(query, updat_command, (err) => {
if (err) {
console.log("Error : while pushing car to the compay's cars");
throw new Error(err);
}
console.log(index, "<<<<<<<< INDEX ", totalCar);
if (index === totalCar - 1) {
console.log("done");
res.send("build complete");
// build_complete();
}
});
}
});
});
console.log(index, "<<<<<<<< INDEX--OUTER ", totalCar);
});
}
我该如何摆脱困境?
答案 0 :(得分:1)
如果您使用的节点数大于7(我希望如此),则可以使用async / await使此代码更易于处理。您还可以使用mongoose中的findOne,这样就不必处理数组,因为您知道每个结果只有一个。
此代码起作用的诀窍是,它要等到之前的汽车插入数据库后再插入另一辆汽车。
async function map_and_save_cars_in_garage() {
let carList = require("./test.json");
let totalCar = carList.length;
for (let carRecord of carList) {
let company_name = carRecord.make.toLowerCase();
let company_location = "USA";
// build a car
let car = {
model: carRecord.model,
year: carRecord.year,
PriceInINR: carRecord.priceInr,
trim: carRecord.trim,
engine: carRecord.engine,
body: carRecord.body,
color: carRecord.color,
transmission_type: carRecord.transmission,
dealer_id: undefined, // --> just for now
};
let dealer_email = "bitBattle_2018_" + carRecord.DealerID + "_@myKarmaa.com";
try {
let dealer = await DealerModel.findOne({
email: dealer_email
}).exec();
car.dealer_id = dealer._id;
let company = await CompanyModel.findOne({
company_name: company_name
}).exec();
if (!company) {
console.log("No such Company car exists in the garrage --> creating one");
let company = new CompanyModel({
company_name: company_name,
company_location: company_location,
cars: [car]
});
await company.save();
} else {
console.log("Company already exists in garage : add this car with all other cars of this company");
await CompanyModel.updateOne({
_id: company._id
}, {
$push: {
cars: car
}
}).exec();
}
} catch (err) {
throw new Error(err);
}
}
console.log("done");
res.send("build complete");
}
我可以尝试的另一件事不是等待每辆车的创建,而是创建一个包含新插入公司的数组(与数据库相比,该数组将被立即访问),
async function map_and_save_cars_in_garage() {
let carList = require("./test.json");
let totalCar = carList.length;
let newCompanies = {};
for (let carRecord of carList) {
(async function () {
let company_name = carRecord.make.toLowerCase();
let company_location = "USA";
// build a car
let car = {
model: carRecord.model,
year: carRecord.year,
PriceInINR: carRecord.priceInr,
trim: carRecord.trim,
engine: carRecord.engine,
body: carRecord.body,
color: carRecord.color,
transmission_type: carRecord.transmission,
dealer_id: undefined, // --> just for now
};
let dealer_email = "bitBattle_2018_" + carRecord.DealerID + "_@myKarmaa.com";
try {
let dealer = await DealerModel.findOne({
email: dealer_email
}).exec();
car.dealer_id = dealer._id;
// Check for company in newCompanies
let company = newCompanies[company_name];
// If company is not in newcompanies it will be undefined so this if statement will be executed
if (!company) {
// If company is not found in database this will be null
await CompanyModel.findOne({
company_name: company_name
}).exec();
}
// If company is null then create a new one
if (!company) {
console.log("No such Company car exists in the garrage --> creating one");
let company = new CompanyModel({
company_name: company_name,
company_location: company_location,
cars: [car]
});
// Add company to newCompanies
newCompanies[company_name] = company;
await company.save();
} else {
console.log("Company already exists in garage : add this car with all other cars of this company");
await CompanyModel.updateOne({
_id: company._id
}, {
$push: {
cars: car
}
}).exec();
}
} catch (err) {
throw new Error(err);
}
})();
}
console.log("done");
res.send("build complete");
}
这不必等待以前的汽车被添加到数据库中。