Mongoose Map type incompatible with TypeScript type - node.js

I have the following interface for model schema:
import { Document } from 'mongoose';
export interface ILog {
tags: { [key: string]: string }[];
}
export interface ILogDocument extends ILog, Document {}
And there is the schema:
const logSchema = new Schema<ILogDocument>({
tags: { type: Map, of: String },
});
So i get the following type error on my schema:
TS2322: Type '{ type: MapConstructor; of: StringConstructor; }' is not assignable to type 'SchemaDefinitionProperty<{ [key: string]: string; }[]> | undefined'.
I want to use proper type defintion, I tried type: Schema.Types.Mixed and its works, but is there a better way to specify mongoose type for tags: { [key: string]: string }[] ?

{ [key: string]: string }[] is not exactly Map. You can use the Map type from TS.
import { Document, Schema } from 'mongoose';
export interface ILog {
tags: Map<string, string>;
}
export interface ILogDocument extends ILog, Document {}
const logSchema = new Schema<ILogDocument>({
tags: { type: Map, of: String }
});

Related

How to change the interface key: value: string to [{ [key: string]: string }

I have interface
IUser {
name: string;
surname: string;
cityLocation: string;
}
the value will be
const user: IUser = {
"name": "John";
"surname": "Smith";
"cityLocation": "LA";
}
I have adapter, they have method which receive
function adapter(columns: { [key: string]: string }) {...}
when I try to do:
adapter(user);
I have error:
Argument of type 'IUser' is not assignable to parameter of type '{ [key: string]: string; }'.   Index signature is missing in type 'IUser'.
How can I fix it?
(funny, but when I dont use signature IUser for object user - adapter works...)
Hope for your help. Big Thx!
As the error says, Index signature is missing in type 'IUser' so add it:
interface IUser {
name: string;
surname: string;
cityLocation: string;
[key: string]: string;
}
Playground link

NestJS Prisma - Types of property entities incompatible, missing or not assigned

I'm trying to update my Postgres database using Prisma ORM in NestJS (Microservices architecture).
The code allows users to interact with invitation requests.
But I keep getting the error:
Argument of type 'Invitation' is not assignable to parameter of type 'Invitation & { work: Work; }'. Property 'work' is missing in type 'Invitation' but required in type '{ work: Work; }'.
The Full error message looks like this:
Type '{ status: "PENDING" | "ACCEPTED" | "REJECTED"; work: undefined; id: string; workId: string; coId?: string; createdAt: Date; respondedAt?: Date; owner?: string; note?: string; }' is not assignable to type '(Without<InvitationUpdateInput, InvitationUncheckedUpdateInput> & InvitationUncheckedUpdateInput) | (Without<...> & InvitationUpdateInput)'.
Type '{ status: "PENDING" | "ACCEPTED" | "REJECTED"; work: undefined; id: string; workId: string; coId?: string; createdAt: Date; respondedAt?: Date; owner?: string; note?: string; }' is not assignable to type 'Without<InvitationUncheckedUpdateInput, InvitationUpdateInput> & InvitationUpdateInput'.
Type '{ status: "PENDING" | "ACCEPTED" | "REJECTED"; work: undefined; id: string; workId: string; coId?: string; createdAt: Date; respondedAt?: Date; owner?: string; note?: string; }' is not assignable to type 'Without<InvitationUncheckedUpdateInput, InvitationUpdateInput>'. Types of property 'workId' are incompatible. Type 'string' is not assignable to type 'never'.
How can I fix this?
Thanks in advance!
The Invitation Interface:
export default class Invitation {
id: string;
workId: string;
work: string;
co?: string;
status: RequestStatus;
createdAt: Date;
respondedAt?: Date;
owner?: string;
note?: string;
}
export enum RequestStatus {
PENDING = 'PENDING',
REJECTED = 'REJECTED',
ACCEPTED = 'ACCEPTED',
}
The prisma invitation schema:
model Invitation {
id String #id #db.Uuid
workId String #db.Uuid
work Work #relation(...)
status RequestStatus
co String #db.Uuid
owner String
note String
createdAt DateTime
respondedAt DateTime
}
The Updating mechanics in Postgres Persistence Infrastructure:
async update(invitation: Invitation): Promise<Invitation> {
const entity = await this.prismaService.invitation.update({
where: {
id: invitation.id,
},
data: {
...invitation,
status: RequestStatusEntity[invitation.status],
work: undefined,
},
include: {
work: true,
},
});
return this.toDomain(entity);
}
private toDomain(
entity: InvitationEntity & {
work: WorkEntity;
},
): Invitation {
return Object.setPrototypeOf(
{
...entity,
status: RequestStatus[entity.status],
},
Invitation.prototype,
);
}
You cannot use TypeScript enums in this case as Prisma uses string literals in the generated type.
I would suggest using Prisma's types directly instead of creating your own like this:
import { RequestStatus } from '#prisma/client'
export default class Invitation {
id: string;
workId: string;
work: string;
co?: string;
status: RequestStatus;
createdAt: Date;
respondedAt?: Date;
owner?: string;
note?: string;
}

Issue with Date and Mongoose Typescript

I'm facing the issue with the Mongoose official document founded here.
import { Schema, Model, model } from 'mongoose';
export interface IUser {
name: string;
email: string;
avatar?: string;
created: Date;
}
const schema = new Schema<IUser, Model<IUser>, IUser>({
name: { type: String, required: true },
email: String,
avatar: String,
created: { type: Date, default: Date.now },
});
export const UserModel = model<IUser>('User', schema);
My problem is the created type in IUser is not the same as in schema and got the error:
Type '{ type: DateConstructor; default: () => number; }' is not assignable to type 'typeof SchemaType | Schema<any, any, undefined, unknown> | Schema<any, any, undefined, unknown>[] | readonly Schema<any, any, undefined, unknown>[] | Function[] | ... 6 more ... | undefined'.
Types of property 'type' are incompatible.
Type 'DateConstructor' is not assignable to type 'Date | typeof SchemaType | Schema<any, any, undefined, unknown> | undefined'.
Type 'DateConstructor' is missing the following properties from type 'typeof SchemaType': cast, checkRequired, set, getts(2322)
(property) created?: typeof SchemaType | Schema<any, any, undefined, unknown> | Schema<any, any, undefined, unknown>[] | readonly Schema<any, any, undefined, unknown>[] | Function[] | ... 6 more ... | undefined
Please let me know how to fix this.
Date.now() is a function which returns number. Instead of it, try using new Date() only. Also need to make changes in the type of createdAt to Number.
In the given doc link, createdAt field type is number but here you have written Date.
interface User {
name: string;
email: string;
avatar?: string;
createdAt: number;
}
OR
createdAt and updatedAt are timestamps which can be used directly without specifying in the schema.
const schema = new Schema<IUser, Model<IUser>, IUser>({
name: { type: String, required: true },
email: String,
avatar: String
},{
timestamps: true
});
I think this is working
import { Schema,Document } from 'mongoose';
export interface IUser {
name: string;
email: string;
avatar?: string;
created: Date;
}
const schema = new Schema<IUser>({
name: { type: String, required: true },
email: String,
avatar: String,
created: { type: Date, default: Date.now },
});
export const UserModel = model<IUser>('User', schema);

How to define ObjectId in DTO & what is the right query to get relational data in NestJS Mongoose?

I'm setting up an app using NestJS, Angular, GraphQL and MongoDB and new to these stacks
I have 2 collections called Tasks & Statuses with sample data
Tasks
[{
"_id": {
"$oid": "5f9138f71163a739c43fc9b3"
},
"TaskDesc": "Meeting with Brian",
"StartedDate": "2020-10-22T07:42:40Z",
"EndDate": "2020-10-22T10:42:40Z",
"StatusId": "5f91375d1163a739c43fc9af"
}]
Statuses
[{
"_id": {
"$oid": "5f91375d1163a739c43fc9af"
},
"StatusDesc": "Done"
}]
Here are schemas defined in NestJS
import { Schema, Types } from 'mongoose';
import { MongooseModule } from '#nestjs/mongoose';
export const TaskSchema = new Schema({
TaskDesc: String,
StartedDate: String,
EndDate: String,
StatusId:
{
type: Types.ObjectId,
ref: 'Statuses'
}
});
export const StatusSchema = new Schema({
StatusDesc: String
});
export const SchemaGroups = MongooseModule.forFeature([
{name: 'Tasks', schema: TaskSchema, collection: 'Tasks'},
{name: 'Statuses', schema: StatusSchema, collection: 'Statuses'}
]);
The DTO
import { ObjectType, Field, ID } from '#nestjs/graphql';
#ObjectType()
export class TasksDTO {
#Field(() => ID)
id?: string;
#Field()
TaskDesc: string;
#Field()
StartedDate: string;
#Field()
EndDate: string;
#Field()
StatusId: string;
}
#ObjectType()
export class StatusDTO {
#Field(() => ID)
readonly id?: string;
#Field()
readonly StatusDesc: string;
}
The model
import { Document, Schema } from 'mongoose';
export interface Tasks extends Document {
readonly TaskDesc : string,
readonly StartedDate: string,
readonly EndDate: string,
readonly StatusId: Schema.Types.ObjectId
}
export interface Status extends Document {
readonly StatusDesc : string
}
The resolver
#Resolver('Tasks')
export class ListTodoResolver {
constructor(private readonly todoItemsService: TodolistService){
}
#Query(() => [TasksDTO])
async Tasks(): Promise<TasksDTO[]> {
return await this.todoItemsService.getAllTasks();
}
#Query(() => [StatusDTO])
async Statuses(): Promise<StatusDTO[]>{
return await this.todoItemsService.getAllStatuses();
}
}
The service
import { Injectable } from '#nestjs/common';
import { InjectModel } from '#nestjs/mongoose';
import { Model } from 'mongoose';
#Injectable()
export class TodolistService {
constructor(
#InjectModel('Tasks') private readonly todoItemsModel: Model<Tasks>,
#InjectModel('Statuses') private readonly statusItemsModel: Model<Status>
) { }
async getAllTasks() : Promise<Tasks[]>{
let tasks = await this.todoItemsModel.find().exec(); // how should we query in the service to get relational data from another collection?
console.log(tasks);
return tasks;
}
async getAllStatuses() : Promise<Status[]>{
return await this.statusItemsModel.find().exec();
}
}
And I had these errors
Type 'Tasks' is not assignable to type 'TasksDTO'. Types of property 'StatusId' are incompatible. Type 'ObjectId' is not assignable to type 'string'.
How do we define the ObjectId type in the DTO ?
My expected output for getAllTasks() method would be
[{
"_id": "5f9138f71163a739c43fc9b3",
"TaskDesc": "Meeting with Brian",
"StartedDate": "2020-10-22T07:42:40Z",
"EndDate": "2020-10-22T10:42:40Z",
"StatusDesc": "Done"
}]
The error is already show where you should fix it.
Type 'Tasks' is not assignable to type 'TasksDTO'. Types of property 'StatusId' are incompatible. Type 'ObjectId' is not assignable to type 'string'.
Which mean your DTO should be
#ObjectType()
export class TasksDTO {
#Field(() => ID)
id?: string;
#Field()
TaskDesc: string;
#Field()
StartedDate: string;
#Field()
EndDate: string;
#Field()
StatusId: objectId; // change here
}
Not sure the object Id type in your DTO, try to look up in the documentation to see if there are Object ID type for the DTO if not you should change StatusId for all place to string and that should work

How to represent an ES6 Map in a Mongoose.js Schema

I'm using an ES6 Map for the "specs" property, which I've represented as seen below in my TypeScript interface:
import { IModel } from './model';
export interface IProduct extends IModel {
name: string;
description: string;
specs: {[key: string]: string };
img: string[];
}
That doesn't seem to work in the mongoose Schema, though. After that failed, I tried the below code in my Schema, which doesn't seem to work either:
const ProductSchema = new Schema({
name: String,
description: String,
specs: [{key: String, value: String}],
img: String[]
});
If someone could help me figure out the correct way to do this, I would be very grateful.

Resources