如何从 mongodb 数组中删除损坏的引用?

How to delete broken references from mongodb array?

我的软件出现错误,导致 mongodb 中的引用损坏。 示例网站文档:

{
"_id" : ObjectId("58d55766f12ba71c4131468a"),
"name" : "abc",
"annotations" : [ 
  ObjectId("58d5580b507af01cc77c5155"), 
  ObjectId("58d55888b83e461d768fc0eb"), 
  ObjectId("58d8d0b434f0b621272869be"), 
  ObjectId("58d8d0f034f0b621272869bf")
]

其中数组中的某些 ObjectId 不再存在。 我试图找到一种方法来删除对注释对象的损坏引用。 这就是我想要做的:

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

我无法使 Promise.all 工作。它在查找函数的 .then 之前执行。 请帮我找出错误。

是否有更优雅的方法使用普通 mongodb 来做到这一点?

谢谢

这并不是一个真正的答案,而是我将如何使用 Async.js 和 Lodash 来完成它的一般想法。

我并没有真正使用 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
    });
});

我在比较两个 ObjectID 数组时遇到问题,所以我将它们转换为字符串以防万一。

我不确定为什么问题中的示例不起作用。但: 这是最终起作用的:

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