如何使用 Typescript 在 mongoose 中正确输入对象 ID 数组

Tia*_*dão 7 mongoose mongodb typescript

我有一个帖子模型:

const PostSchema = new Schema<IPost>(
  {
    // ...
    likes: [{ type: Schema.Types.ObjectId, ref: "User" }],
    // ...
  }
)

export default model<IPost>("Post", PostSchema)
Run Code Online (Sandbox Code Playgroud)
export interface IPost {
  // ...
  likes: ObjectId[]
  // ...
}

export interface IPostDocument extends Document, IPost {}
Run Code Online (Sandbox Code Playgroud)

我正在尝试切换用户,例如:

export const toggleLike: TController = async (req, res, next) => {
  const user = req.user as IUserDocument;
  const userId = user._id;
  const postId = req.params.postId;
  try {
    const disliked = await PostModel.findOneAndUpdate(
      { _id: postId, likes: userId },
      { $pull: { likes: userId } }
    ); // works with no problem
    if (disliked)
      res.json({ message: `User ${userId} disliked post ${postId}` });
    else {
      const liked = await PostModel.findOneAndUpdate(
        { _id: postId },
        { $push: { likes: userId } }
      ); // the $push throws an error "Type instantiation is excessively deep and possibly infinite."
      if (liked) res.json({ message: `User ${userId} liked post ${postId}` });
      else return next(createError(404, "Post not found"));
    }
  } catch (error) {
    next(createError(500, error as Error));
  }
};
Run Code Online (Sandbox Code Playgroud)

mongo $push 运算符抛出错误“类型实例化过深且可能无限”。

我怀疑这有帮助,但错误的描述是:

(属性)喜欢?: _AllowStringsForIds<((((((((((... | 任何[])[] | 任何[])[] | 任何[])[] | 任何[])[] | 任何[])[] | 任何[])[] | 任何[])[] | 任何[])[] | 任何[])[] | 任何[])[] | 任何[])[] | 任何[]> | ArrayOperator<(_AllowStringsForIds<(((((((((... | 任何[])[] | 任何[])[] | 任何[])[] | 任何[])[] | 任何[ ])[] | 任何[])[] | 任何[])[] | 任何[])[] | 任何[])[] | 任何[])[] | 任何[])[] | 任何[] > | 未定义)[]> | 不明确的

知道发生了什么吗?

Ale*_*Dim 5

我想你的问题与我的这个问题非常相关:Nestjs: Correct schema for array of subdocuments in mongoose (without default _id or redefine ObjectId)。除了我不想拥有,ObjectID但你却想要。

问题是MongooseDocument<Array>和 TSArray非常相似,但方法不同。

我正在使用 Nestjs,所以我将提供一个示例,但我想您发现我的示例非常有用。

例如,对于嵌入文档数组,您需要具有以下模式接口:

在子模式中:

@Schema()
class Field extends Document {
  @Prop({ type: MongooseSchema.Types.ObjectId })
  _id: MongooseSchema.Types.ObjectId

  @Prop({ type: String })
  name: string;
}

export const FieldSchema = SchemaFactory.createForClass(Field);
Run Code Online (Sandbox Code Playgroud)

在父架构中:

  @Prop({ _id: true, type: [FieldSchema] })
  field: MongooseSchema.Types.Array<Field>;
Run Code Online (Sandbox Code Playgroud)

最重要的部分是进口:

import { Document, Schema as MongooseSchema, Types } from "mongoose";
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
Run Code Online (Sandbox Code Playgroud)

当然,在默认的 TS 项目中,如果没有 Nest.js,您就没有 Nest.js nest/mongoose,但正如您可能已经了解的那样,一切都与我们从自身获取的接口及其类型相关mongoose

classSchema 接口也是如此,它是从 mongooseDocument接口扩展而来的,所有数组不仅仅是普通的 TS 数组,而是 Schema.Types.Array (来自 mongoose)。根据文档,您不仅可以使用ObjectId,还可以使用其他特殊的 Mongo 专用类型,例如Decimal128数字Mixed等。

因此,在使用 ObjectId 数组的情况下,您只需要使用:

MongooseSchema.Types.Array<MongooseSchema.Types.ObjectId>
Run Code Online (Sandbox Code Playgroud)

对象 ID 数组

或者更原始的方式:

对象 ID 数组2

在 @Prop 装饰器的 Nest 中,您为 mongoDB 字段类型提供类型,因此它与默认 TS 相同:new Schema({ languages: { type: ObjectId} })

所以我希望它能对您的项目有所帮助。


Ham*_*RIM 2

我不确定,但它可能很有趣:类型脚本端可能期望其他项目出现在那里,因为它集中作为一个数组。

您可以尝试使用 every { $push: { : { $each: [ , ... ] } } }

value1 在你的位置上就足够了