[英]How to delete broken references from mongodb array?
I had an error in my software leading to broken references in my mongodb. 我的软件出现错误,导致mongodb中的引用损坏。 An example website document:
一个示例网站文档:
{
"_id" : ObjectId("58d55766f12ba71c4131468a"),
"name" : "abc",
"annotations" : [
ObjectId("58d5580b507af01cc77c5155"),
ObjectId("58d55888b83e461d768fc0eb"),
ObjectId("58d8d0b434f0b621272869be"),
ObjectId("58d8d0f034f0b621272869bf")
]
Where some of the ObjectIds in the array don't exist any more. 数组中某些ObjectId不再存在的地方。 I'm trying to find a way to delete the broken references to the annotation object.
我正在尝试找到一种方法来删除对注释对象的损坏的引用。 This is what I'm trying to do:
这就是我想要做的:
const mongoose = require('mongoose');
const config = require('config');
const Promise = require('bluebird');
mongoose.Promise = Promise;
mongoose.connect(config.get("DBUrl"), {useMongoClient: true});
require('./model/Website');
require('./model/Annotation');
const Website = mongoose.model('Website');
const Annotation = mongoose.model('Annotation');
Website.find({})
.then(function (websites) {
for (let website of websites) {
let queue = [];
for (let annotationId of website.annotations) {
queue.push(Annotation.find({_id: annotationId}, {_id: 1})
.then(function (ann) {
if (!ann) {
website.pull(annotationId);
}
return Promise.resolve(website);
})
);
}
Promise.all(queue)
.then(function (ws) {
console.log('updated website ' + website.name)
return website.save();
})
.catch(function (err) {
throw new Error(err);
});
}
});
I can't get the Promise.all working. 我无法实现Promise.all。 It's executed before the .then of the find functions.
它在find函数的.then之前执行。 Please help me to find the error.
请帮助我找到错误。
Is there maybe a more elegant way to do this using plain mongodb? 使用纯mongodb可能有更优雅的方法吗?
Thank You 谢谢
This is not really an answer but a general idea of how I would do it using Async.js and Lodash. 这不是一个真正的答案,而是关于我将如何使用Async.js和Lodash进行操作的总体思路。
I don't really use Bluebird (and by the looks of their documentation, I doubt I ever will). 我并没有真正使用Bluebird(从他们的文档来看,我怀疑我会不会使用)。
async.series([
// get all annotation IDs
done => Annotation.distinct('_id').exec(done),
// get all websites
done => Website.find({}).exec(done)
], function (err, results) {
let annotationIDs = results[0].map(String),
websites = results[1];
// loop through each website
async.eachSeries(websites, function (website, done) {
// reset the annotations with only ones that exist
website.annotations = _.intersection(website.annotations.map(String), annotationIDs)
website.save(done);
}, function (err) => {
// all done
});
});
I've had issues comparing two arrays of ObjectIDs, so I cast them to Strings just in case. 比较两个ObjectID数组时遇到问题,因此我将它们强制转换为String以防万一。
I'm not sure why the example in the question doesn't work. 我不确定问题中的示例为何不起作用。 But: Here is what worked in the end:
但是:这是最终有效的方法:
Website.find({})
.then(function (websites) {
for (let website of websites) {
let queue = [];
for (let annotationId of website.annotations) {
queue.push(Annotation.find({_id: annotationId}, {_id: 1})
.then(function (ann) {
if (!ann) {
website.pull(annotationId);
}
return Promise.resolve(website);
})
);
}
Promise.all(queue)
.then(function (ws) {
console.log('updated website ' + website.name)
return website.save();
})
.catch(function (err) {
throw new Error(err);
});
}
});
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.