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

Posted

技术标签:

【中文标题】如何使用 Typescript 在 mongoose 中正确键入对象 ID 数组【英文标题】:How to properly type array of object IDs in mongoose with Typescript 【发布时间】:2021-11-27 17:12:40 【问题描述】:

我有一个帖子模型:

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

export default model<IPost>("Post", PostSchema)
export interface IPost 
  // ...
  likes: ObjectId[]
  // ...


export interface IPostDocument extends Document, IPost 

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

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

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

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

(属性)喜欢?任意[])[] |任意[])[]|任意[])[]|任意[])[]|任意[])[]|任意[])[]|任意[])[]|任意[])[] |任何[]> | ArrayOperator | 未定义)[]> |未定义

知道发生了什么吗?

【问题讨论】:

您介意以有效的 JSON 格式共享示例数据吗? 错误提示数据库中的数据不是单级数组,而是数组数组。实际上可能是数组数组数组数组数组数组数组数组数组等等。 你能添加你的依赖版本的细节吗?我创建了一个最小的复制here,它适用于"mongoose": "^6.0.11""@types/mongoose": "^5.11.97""typescript": "^4.4.4" 感谢您的 cmets,但问题已解决。在我的界面上,我使用了 ObjectId,但没有从任何地方导入它。一旦我从猫鼬导入它,一切正常。我不知道我使用的另一个 ObjectId 是什么... 【参考方案1】:

我不确定,但可能会很有趣:类型脚本方面可能期望其他项目出现,因为它以数组的形式聚焦。

您可以尝试使用每个 $push: : $each: [ , ... ]

value1 在你的位置上就足够了

【讨论】:

【参考方案2】:

在我的接口声明中从 mongoose 导入 ObjectId 解决了这个问题。在此之前,我一直在使用它,但没有从任何地方导入它(我什至不知道那是什么)。

【讨论】:

【参考方案3】:

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

问题是MongooseDocument&lt;Array&gt; 和 TS Array 非常相似,但方法不同。

我正在使用 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);

在父架构中:

  @Prop( _id: true, type: [FieldSchema] )
  field: MongooseSchema.Types.Array<Field>;

最重要的部分是导入:

import  Document, Schema as MongooseSchema, Types  from "mongoose";
import  Prop, Schema, SchemaFactory  from '@nestjs/mongoose';

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

所以class是一个Schema接口,它是从猫鼬Document接口扩展而来的,所有的数组都不仅仅是普通的TS数组,而是Schema.Types.Array(来自mongoose)。您不仅可以使用 ObjectId,还可以使用其他特殊的 Mongo 专用类型,例如 Decimal128 数字和 Mixed 等等,according to the docs。

所以在你使用 ObjectIds 数组的情况下,你只需要使用:

MongooseSchema.Types.Array<MongooseSchema.Types.ObjectId>

或者更原始的方式:

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

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

【讨论】:

以上是关于如何使用 Typescript 在 mongoose 中正确键入对象 ID 数组的主要内容,如果未能解决你的问题,请参考以下文章

将 2 列中的 json 数据与模式中的数据进行比较,并将最新数据覆盖为 mongoos 中的主要数据

Moogose的基本连接以及增删改查操作

如何在 Vue (Typescript) 中使用 axios?

如何在 TypeScript 中使用 RequestPromise?

如何在 Typescript 2.1+ 中使用 Bluebird

如何在Vue项目中使用Typescript