使用 Typescript 在 Mongoose 中缺少子文档方法

vmh*_*hes 4 mongoose mongodb typescript

我正在处理一个项目,需要通过它们的子文档从模型中检索特定的子文档_id。然后我计划更新这些子文档并保存主文档。mongoose 子文档文档列出了许多您可以在parent.children数组上调用的方法,但是在 Javascript 中不存在数组的方法会给出错误,指出它们不存在并且无法编译。我参考了这个文档:https : //mongoosejs.com/docs/subdocs.html

我知道应该能够用来.findOneAndUpdate进行更新,并且使用该runValidators选项仍然应该验证所有内容,但我也想只检索子文档本身。

我看了这篇文章:MongoDB, Mongoose: How to find subdocument in found document? ,我将评论答案是不正确的,如果注册了子文档模式,它会自动为该模式创建一个集合,只有在单独保存该模式时才会创建该集合。您不能使用ChildModel.findOne()和检索子文档,因为该集合不存在,其中没有任何内容。

拥有IChildModel扩展mongoose.Types.Subdocument并拥有IParent接口引用,而不是IChild和不注册ChildModel除了不再允许调用.push()不接受简单对象(缺少 30 个左右的属性)之外不会改变任何事情。同样mongoose.Types.Array<IChild>IParent界面中尝试使用此方法不会改变任何内容。

更改用于属性的IParent接口允许工作,但不能或mongoose.Types.Array<IChild>childrenaddToSet()id()create()

我使用的是 Mongoose 版本5.5.10、MongoDb 版本4.2.0和 Typescript 版本3.4.5

import mongoose, { Document, Schema } from "mongoose";

// Connect to mongoDB with mongoose
mongoose.connect(process.env.MONGO_HOST + "/" + process.env.DB_NAME, {useNewUrlParser: true, useFindAndModify: false});

// Interfaces to be used throughout application
interface IParent {
    name: string;
    children: IChild[];
}

interface IChild {
    name: string;
    age: number;
}

// Model interfaces which extend Document
interface IParentModel extends IParent, Document { }
interface IChildModel extends IChild, Document { }

// Define Schema
const Child: Schema = new Schema({
    name: {
        type: String,
        required: true
    },
    age: {
        type: Number,
        required: true
    }
});

const ChildSchema: Schema = Child;

const Parent: Schema = new Schema({
    name: {
        type: String,
        required: true
    },
    children: [ChildSchema]
});

const ParentSchema: Schema = Parent;

// Create the mongoose models
const ParentModel = mongoose.model<IParentModel>("Parent", Parent);
const ChildModel = mongoose.model<IChildModel>("Child", Child);

// Instantiate instances of both models
const child = new ChildModel({name: "Lisa", age: 7});
const parent = new ParentModel({name: "Steve", children: [child]});

const childId = child._id;

// Try to use mongoose subdocument methods
const idRetrievedChild = parent.children.id(childId); // Property 'id' does not exist on type 'IChild[]'.ts(2339)
parent.children.addToSet({ name: "Liesl", age: 10 }); // Property 'addToSet' does not exist on type 'IChild[]'.ts(2339)
parent.children.create({ name: "Steve Jr", age: 2 }); // Property 'create' does not exist on type 'IChild[]'.ts(2339)

// If I always know the exact position in the array of what I'm looking for
const arrayRetrievedChild = parent.children[0]; // no editor errors
parent.children.unshift(); // no editor errors
parent.children.push({ name: "Emily", age: 18 }); // no editor errors
Run Code Online (Sandbox Code Playgroud)

Dre*_*rei 9

有点迟到的回复,但我查看了打字并找到了 DocumentArray

import { Document, Embedded, Types } from 'mongoose';
interface IChild extends Embedded {
    name: string;
}

interface IParent extends Document {
    name: string;
    children: Types.DocumentArray<IChild>;
}
Run Code Online (Sandbox Code Playgroud)

只是想把它放在这里以防其他人需要它。

  • 几乎,您只需要使用Embedded而不是Document for IChild。这样,除了常用的文档方法之外,您还可以访问子文档方法,例如parent()和ownerDocument()。 (2认同)
  • 在“Types.Embedded”中找到“Embedded” (2认同)
  • 看起来这些天(Mongoose 6)“Types.Subdocument”就是您所需要的 - “Types.Embedded”不再存在 (2认同)