【问题标题】:How to delete broken references from mongodb array?如何从 mongodb 数组中删除损坏的引用?
【发布时间】:2017-08-08 03:57:58
【问题描述】:

我的软件出现错误,导致 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 是否有更优雅的方法来做到这一点?

谢谢

【问题讨论】:

  • 我会跳过第二个 for 循环(website.annotations 的annotationId),而是进行Annotation.find({_id: {$in: website.annotations}}) 之类的查询,然后将查询结果与原始列表进行比较。如果您不担心竞争条件,您可以将 website.annotations 设置为结果数组。如果需要,也许可以查看 lodash 以轻松找到两个数组之间的区别(确保在比较它们之前使用 .toString() objectIds)我也会考虑在这里使用 async 或流而不是 promise.all (尤其是当网站数量可以大)

标签: javascript node.js mongodb mongoose bluebird


【解决方案1】:

这并不是一个真正的答案,而是一个关于如何使用 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 数组时遇到了问题,因此我将它们转换为字符串以防万一。

【讨论】:

    【解决方案2】:

    我不确定为什么问题中的示例不起作用。但: 最终效果如下:

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

    【讨论】:

      猜你喜欢
      • 2014-02-08
      • 1970-01-01
      • 2017-01-18
      • 2015-09-30
      • 1970-01-01
      • 1970-01-01
      • 2014-01-17
      • 1970-01-01
      • 2020-04-16
      相关资源
      最近更新 更多