Mongoose嵌套模式数组 - 对象没有方法' id'

时间:2014-06-22 15:21:48

标签: node.js mongoose

我试图在Mongoose中定义文件夹架构。对于每个文件夹,我想存储对父文件夹的引用,以及子子文件夹的数组(以便在任一方向上进行遍历):

var folderSchema = new mongoose.Schema({
    name: String,
    parent: { type: Schema.Types.ObjectId, ref: 'Folder' },
    subfolders: [{ type: Schema.Types.ObjectId, ref: 'Folder' }],
});

创建文件夹时,我希望只能指定父文件夹,然后让pre-save hook注意将子文件夹添加到父文件夹的subfolders数组中。这部分工作正常:

folderSchema.pre('save', function (next) {
    var self = this;

    // If creating a subfolder, then add the subfolder to
    // the parent folder's "subfolders" array

    if (this.parent) {
        Folder.findById(this.parent, function (err, parent) {
            if (err) return next(err);
            if (parent) {
                parent.subfolders.push(self);
                return parent.save(next);
            }
            return next();
        });
    } else {
        next();
    }
});

此外,删除子文件夹时,我想使用预删除挂钩自动从父文件夹的subfolders数组中删除子文件夹。不幸的是,我无法让这部分工作:

folderSchema.pre('remove', function (next) {
    var self = this;

    // If deleting a subfolder, then remove it from the parent
    // folder's "subfolders" array
    //
    // (Note: it would also be a good idea to recursively remove
    // all subfolders here, but I'm not attempting this yet.)

    if (this.parent) {
        Folder.findById(this.parent, function (err, parent) {
            if (err) return next(err);
            if (parent) {
                parent.subfolders.id(self._id).remove();    // TypeError: Object 53a64349741d1ae82274c9a2 has no method 'id'
                return parent.save(next);
            }
            return next();
        });
    } else {
        next();
    }
});

错误的一行就是这一行:

parent.subfolders.id(self._id).remove();

导致此错误:

TypeError: Object 53a64349741d1ae82274c9a2 has no method 'id'
    at Promise.<anonymous> (C:\Users\serg\temp\mongoose\folders\index.js:53:35)
    at Promise.<anonymous> (C:\Users\serg\temp\mongoose\folders\node_modules\mongoose\node_modules\mpromise\lib\promise.js:177:8)
    at Promise.EventEmitter.emit (events.js:95:17)
    at Promise.emit (C:\Users\serg\temp\mongoose\folders\node_modules\mongoose\node_modules\mpromise\lib\promise.js:84:38)
    at Promise.fulfill (C:\Users\serg\temp\mongoose\folders\node_modules\mongoose\node_modules\mpromise\lib\promise.js:97:20)
    at C:\Users\serg\temp\mongoose\folders\node_modules\mongoose\lib\query.js:1393:13
    at model.Document.init (C:\Users\serg\temp\mongoose\folders\node_modules\mongoose\lib\document.js:250:11)
    at completeOne (C:\Users\serg\temp\mongoose\folders\node_modules\mongoose\lib\query.js:1391:10)
    at Object.cb (C:\Users\serg\temp\mongoose\folders\node_modules\mongoose\lib\query.js:1150:11)
    at Object._onImmediate (C:\Users\serg\temp\mongoose\folders\node_modules\mongoose\node_modules\mquery\lib\utils.js:137:16)

我尝试做的是使用MongooseDocumentArray#id方法删除子文档,如Mongoose文档的Sub Docs页面上的示例所示。但是,看起来这种方法不可用,我不确定为什么会这样。我是否错误地定义了架构?中间件中是否没有id方法?或者我只是没有正确使用它?

1 个答案:

答案 0 :(得分:5)

这里的不同之处在于您使用的是对数组中对象的嵌入式引用,而不是直接子文档。在子文档的猫鼬示例中,它显示:

var childSchema = new Schema({ name: 'string' });

var parentSchema = new Schema({
  children: [childSchema]
});

因此,在此示例中,每个“子”实际上直接存储在“父”中(因此子项存在于父集合中)。在您的方案中,您引用了subfolders ID,而不是直接存储对象:

subfolders: [{ type: Schema.Types.ObjectId, ref: 'Folder' }],

因此,当您执行查询时,subfolders中的结果实际上是一个ID数组,其中一个是53a64349741d1ae82274c9a2。这没有导致问题的方法id。但是,您可以使用populate填充这些ID的对象。但即使这样做也不会为您提供所需的DocumentArray功能,因为猫鼬只将Array视为DocumentArray,而不是id(会有Array你正在寻找的功能)。 You can see the logic which it uses to determine how to cast these objects here。最后,你会看到当你加载这些对象时,mongoose将它们转换为return new Types.Array(path, cast || Types.Mixed, obj); 类型:

id

因此,如果您需要此{{1}}功能,则可以更改架构,或者只是执行它所做的工作。 The logic isn't that much,因此您可以考虑仅在数组中搜索与该ID匹配的那个。