Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Typescript: How to represent populated document fields on newly-constructed documents #11758

Closed
ajwootto opened this issue May 3, 2022 · 3 comments
Labels
enhancement This issue is a user-facing general improvement that doesn't fix a bug or add a new feature typescript Types or Types-test related issue / Pull Request
Milestone

Comments

@ajwootto
Copy link

ajwootto commented May 3, 2022

Do you want to request a feature or report a bug?
feature? or question

What is the current behavior?
When constructing a new document which has a foreign key field that could be populated, sometimes I will construct the document using the full foreign document rather than just _id. I would then like to use the fields from that "populated" document from the resulting document I've constructed. However, the type system thinks that field is just an "_id". The only way I know how to get the document in its "populated" form would be to go and query for it using the populate method, and provide the populated "paths" object there. I obviously don't want to go and re-fetch the document I've just made, so is there any way to define that this field is populated on creation?

If the current behavior is a bug, please provide the steps to reproduce.

import { Schema, model, connect, Types } from 'mongoose'

interface NestedChild {
    name: string
    _id: Types.ObjectId
}
const nestedChildSchema: Schema = new Schema({ name: String })

interface Parent {
    nestedChild: Types.ObjectId
    name?: string
}

const ParentModel = model<Parent>('Parent', new Schema({
    nestedChild: { type: Schema.Types.ObjectId, ref: 'NestedChild' },
    name: String
}))

const NestedChildModel = model<NestedChild>('NestedChild', nestedChildSchema)

async function run() {
    await connect('mongodb://localhost:27017/')
    const parent = new ParentModel({
        nestedChild: new NestedChildModel({ name: 'test' }),
        name: 'Parent'
    })

    await parent.save()

    // doesn't work, nestedChild is expected to be an object id
    console.log(parent.nestedChild.name)
}

run()

What is the expected behavior?
I would like there to be a way to specify the "paths" on model construction similarly to "populate" so that documents I'm creating for the first time can be represented properly.

What are the versions of Node.js, Mongoose and MongoDB you are using? Note that "latest" is not a version.
Mongoose 6.3.1

@Uzlopak Uzlopak added the help This issue can likely be resolved in GitHub issues. No bug fixes, features, or docs necessary label May 3, 2022
@vkarpov15 vkarpov15 added this to the 6.3.5 milestone May 11, 2022
@github-actions
Copy link

This issue is stale because it has been open 14 days with no activity. Remove stale label or comment or this will be closed in 5 days

@github-actions github-actions bot added the Stale label May 26, 2022
@ajwootto
Copy link
Author

not stale

@github-actions github-actions bot removed the Stale label May 27, 2022
@vkarpov15 vkarpov15 modified the milestones: 6.3.5, 6.4 May 28, 2022
@vkarpov15 vkarpov15 added enhancement This issue is a user-facing general improvement that doesn't fix a bug or add a new feature and removed help This issue can likely be resolved in GitHub issues. No bug fixes, features, or docs necessary labels May 28, 2022
vkarpov15 added a commit that referenced this issue May 28, 2022
@AbdelrahmanHafez AbdelrahmanHafez added the typescript Types or Types-test related issue / Pull Request label May 28, 2022
@ajwootto
Copy link
Author

ajwootto commented Aug 4, 2022

@vkarpov15 one issue I'm encountering with the $assertPopulated solution is that it always returns the "interface" representation of the document instance rather than the full document. This causes issues for me when trying to interact with a new document with populated fields, and then call .save()

import { Schema, model, connect, Types } from 'mongoose'

interface NestedChild {
    name: string
    _id: Types.ObjectId
}
const nestedChildSchema: Schema = new Schema({ name: String })

interface Parent {
    nestedChild: Types.ObjectId
    name?: string
}

const ParentModel = model<Parent>('Parent', new Schema({
    nestedChild: { type: Schema.Types.ObjectId, ref: 'NestedChild' },
    name: String
}))

const NestedChildModel = model<NestedChild>('NestedChild', nestedChildSchema)

async function run() {
    await connect('mongodb://localhost:27017/')
    const parent = (new ParentModel({
        nestedChild: new NestedChildModel({ name: 'test' }),
        name: 'Parent'
    })).$assertPopulated<{nestedChild: NestedChild}>('nestedChild')

    // works, assertPopulated makes sure `parent` has a nestedChild field correctly typed
    console.log(parent.nestedChild.name)

   // doesn't work, parent is no longer a Document 
    await parent.save()
}

run()

Should I open a new issue for this?

edit:

changing the definition from this:

$assertPopulated<Paths = {}>(paths: string | string[]): Omit<DocType, keyof Paths> & Paths;

to this:

$assertPopulated<Paths = {}>(paths: string | string[]): Omit<this, keyof Paths> & Paths;

appears to fix the problem for me

edit:
opened a new issue here:
#12234

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement This issue is a user-facing general improvement that doesn't fix a bug or add a new feature typescript Types or Types-test related issue / Pull Request
Projects
None yet
Development

No branches or pull requests

4 participants