我的应用程序变得有点噩梦,这是我在其他地方无法找到的非标准MongoDB问题。
我的服务器流程如下:
{names, emails and company domains}
的对象列表上传到我的服务器Person
个对象。Person
后,我会搜索MongoDB以查看此人Domain
的记录是否存在。Person
的Mongo _id
添加到Domain
的用户列表中。Domain
文档并保存。这在理论上有效,但是,由于Async,有时我会立即向Domain保护程序发送数千个Person
个对象。这意味着(至少,我认为发生了什么):
以下是我目前正在使用的代码:
Domain.findOne({
domain: domn
}, function(err, rec) {
if (err) {
console.log("Domain finding error: " + err)
bigCount.doneDoms++;
checkCount()
} else if (rec){
var tempObj = {}
tempObj['$addToSet'] = { users: id }
tempObj['$addToSet'].emails = user.email;
if (userDoms.indexOf(rec._id) === -1) {
userDoms.push(rec._id)
}
Domain.update({domain: domn}, tempObj, function(err) {
if (err) {
console.log("Old rec save Error: " + err)
bigCount.doneDoms++;
checkCount();
}else{
// Saved Document
}
});
} else {
var newDom = new Domain();
newDom.domain = user.domain;
newDom.company = user.company;
newDom.users = [];
newDom.users.push(id);
newDom.emails = [];
newDom.emails.push(user.email);
newDom.save(function(err, record) {
if (err) {
console.log("Dom save error: " + err)
} else {
// Saved Document
}
});
}
})
也许问题的精简版本是,如何处理这样的事情:
var arr = [{dom: 'dom1.com', user: 'James'}, {dom: 'dom1.com', user: "Phil"}, {dom: 'dom1.com', user: "Jess"} ...x1000... {dom: 'dom1.com', user: "Chris"];
for(var i - 0; i< arr.length; i++){
var dom = arr[i]; var user = arr[i].user;
Domain.findOne({domain: dom}, function(err, rec){
if(rec){
// Update old rec
if(rec.users.indexOf(user) === -1){
rec.users.push(user);
}
rec.save();
]else{
// Make a new rec
var rec = New Domain();
rec.users = [user]
rec.save();
}
})
}
由于速度/异步,这里会创建很多记录,当我真的只想要一个
答案 0 :(得分:2)
我个人会继续采用这种做法,你会采用错误的方法,以及你可以在这里使用一些流量控制。
无论&#34;列表&#34;来源,应该发生的一般流程是:
为用户实例化对象(毕竟你获得了_id
)
查找域数据(如果存在),如果不存在,则在同时添加用户时创建域数据。 (非常可能)
最后将匹配的域添加到用户并保存
这一切都遵循了.findOneAndUpdate()
以及&#34; upsert&#34;选项,如果找不到,将创建一个新文档,并且无论如何都会返回找到或创建的结果文档。
所以对于一些node async库助手,这里是:
var async = require('async'),
mongoose = require('mongoose'),
Schema = mongoose.Schema;
var userSchema = new Schema({
name: { type: String, required: true },
domain: { type: Schema.Types.ObjectId, ref: 'Domain' }
});
var domainSchema = new Schema({
name: { type: String, required: true },
users: [{ type: Schema.Types.ObjectId, ref: 'User' }]
});
var User = mongoose.model('User',userSchema),
Domain = mongoose.model('Domain',domainSchema);
mongoose.connect('mongodb://localhost/domains');
var arr = [
{dom: 'dom1.com', user: "James"},
{dom: 'dom2.com', user: "Phil"},
{dom: 'dom1.com', user: "Jess"},
{dom: 'dom1.com', user: "Chris"},
{dom: 'dom3.com', user: "Jesse"}
];
async.series(
[
// Clean removal of data for demo
function(callback) {
async.each([User,Domain],function(model,callback) {
model.remove({},callback);
},callback);
},
// The actual insertion process
function(callback) {
async.eachLimit(arr,10,function(item,callback) {
var user = new User({ name: item.user });
// user already has the _id
Domain.findOneAndUpdate(
{ "name": item.dom },
{ "$push": { "users": user._id } },
{ "new": true, "upsert": true },
function(err,domain) {
if (err) callback(err);
user.domain = domain._id; // always returns something
// now save the user
user.save(callback);
}
);
},callback);
},
// List back populated as the proof
function(callback) {
User.find({}).populate('domain').exec(function(err,users) {
if (err) callback(err);
//console.log(users);
//callback();
var options = {
path: 'domain.users',
model: 'User'
};
User.populate(users,options,function(err,results) {
if (err) callback(err);
console.log( JSON.stringify( results, undefined, 2 ) );
callback();
});
});
}
],
function(err) {
if (err) throw err;
mongoose.disconnect();
}
);
这将产生如下输出:
[
{
"_id": "55e6aa0e85e8b9102179f5c2",
"domain": {
"_id": "55e6aa0ecb536c5a93574ff5",
"name": "dom1.com",
"__v": 0,
"users": [
{
"_id": "55e6aa0e85e8b9102179f5c2",
"domain": "55e6aa0ecb536c5a93574ff5",
"name": "James",
"__v": 0
},
{
"_id": "55e6aa0e85e8b9102179f5c4",
"domain": "55e6aa0ecb536c5a93574ff5",
"name": "Jess",
"__v": 0
},
{
"_id": "55e6aa0e85e8b9102179f5c5",
"domain": "55e6aa0ecb536c5a93574ff5",
"name": "Chris",
"__v": 0
}
]
},
"name": "James",
"__v": 0
},
{
"_id": "55e6aa0e85e8b9102179f5c3",
"domain": {
"_id": "55e6aa0ecb536c5a93574ff6",
"name": "dom2.com",
"__v": 0,
"users": [
{
"_id": "55e6aa0e85e8b9102179f5c3",
"domain": "55e6aa0ecb536c5a93574ff6",
"name": "Phil",
"__v": 0
}
]
},
"name": "Phil",
"__v": 0
},
{
"_id": "55e6aa0e85e8b9102179f5c4",
"domain": {
"_id": "55e6aa0ecb536c5a93574ff5",
"name": "dom1.com",
"__v": 0,
"users": [
{
"_id": "55e6aa0e85e8b9102179f5c2",
"domain": "55e6aa0ecb536c5a93574ff5",
"name": "James",
"__v": 0
},
{
"_id": "55e6aa0e85e8b9102179f5c4",
"domain": "55e6aa0ecb536c5a93574ff5",
"name": "Jess",
"__v": 0
},
{
"_id": "55e6aa0e85e8b9102179f5c5",
"domain": "55e6aa0ecb536c5a93574ff5",
"name": "Chris",
"__v": 0
}
]
},
"name": "Jess",
"__v": 0
},
{
"_id": "55e6aa0e85e8b9102179f5c5",
"domain": {
"_id": "55e6aa0ecb536c5a93574ff5",
"name": "dom1.com",
"__v": 0,
"users": [
{
"_id": "55e6aa0e85e8b9102179f5c2",
"domain": "55e6aa0ecb536c5a93574ff5",
"name": "James",
"__v": 0
},
{
"_id": "55e6aa0e85e8b9102179f5c4",
"domain": "55e6aa0ecb536c5a93574ff5",
"name": "Jess",
"__v": 0
},
{
"_id": "55e6aa0e85e8b9102179f5c5",
"domain": "55e6aa0ecb536c5a93574ff5",
"name": "Chris",
"__v": 0
}
]
},
"name": "Chris",
"__v": 0
},
{
"_id": "55e6aa0e85e8b9102179f5c6",
"domain": {
"_id": "55e6aa0ecb536c5a93574ff7",
"name": "dom3.com",
"__v": 0,
"users": [
{
"_id": "55e6aa0e85e8b9102179f5c6",
"domain": "55e6aa0ecb536c5a93574ff7",
"name": "Jesse",
"__v": 0
}
]
},
"name": "Jesse",
"__v": 0
}
]
因此,所有域都已创建或在存在时重新使用,我们使用$push
同时将用户添加到列表中,因为我们已经拥有_id
用户创建实例后。
在返回域名文档时,无论是新文档还是找到的文档,您只需在用户上设置域并保存即可。
async.eachLimit
也是一个特殊的&#34; &#34;限制&#34;循环下运行的并发进程数。这是真实场景中的明智做法,因为您不希望同时发生每次更新。
此外,无论过程如何,&#34; Domain&#34;不可能不止一次创建。 MongoDB的原子操作将阻止这种情况,您只能获得现有的返回或新文档,具体取决于请求时的内容。
正如您在输出中所看到的,所有内容都可以很好地填充,以便&#34;用户&#34;和&#34;域&#34;细节在各个层面都可见。
故事的道德是&#34;不要把自己束缚在坚持一件事并且一次又一次地改变&#34; 的结。只做一次,完成它。它肯定更快。
答案 1 :(得分:1)
var items = [
{dom: 'dom1.com', user: "Johnny"},
{dom: 'dom1.com', user: "Doggie"},
{dom: 'dom1.com', user: "Lisa"},
{dom: 'dom2.com', user: "Mark"},
{dom: 'dom3.com', user: "Denny"}
];
async.each(items, function(item, callback){
Domain.findOneAndUpdate(
{domain: item.dom},
{$addToSet: {users: item.user}},
{ "new": true, "upsert": true },
callback
);
},
function (err){
// done / handle errors
}
);
输出:
[{
"_id": ObjectID("55e6c9bf63006d730254ea8b"),
"domain": "dom1.com",
"users": [
"Johnny",
"Doggie",
"Lisa"
]
},
{
"_id": ObjectID("55e6c9bf63006d730254ea8c"),
"domain": "dom2.com",
"users": [
"Mark"
]
},
{
"_id": ObjectID("55e6c9bf63006d730254ea8d"),
"domain": "dom3.com",
"users": [
"Denny"
]
}]