Search code examples
node.jsmongodbbackendschemafeathersjs

Relations in FeathersJS 5 + MongoDB


I ran into a problem again. I'm trying to convert my Express backend to FeathersJS, but I can make schemas relations work.

This is my job.schema.js

// For more information about this file see https://dove.feathersjs.com/guides/cli/service.schemas.html
import { resolve, getValidator, querySyntax } from '@feathersjs/schema'
import { ObjectIdSchema } from '@feathersjs/schema'
import { dataValidator, queryValidator } from '../../validators.js'

// Main data model schema
export const jobSchema = {
  $id: 'Job',
  type: 'object',
  additionalProperties: false,
  required: ['_id', 'jobname'],
  properties: {
    _id: ObjectIdSchema(),
    jobname: { type: 'string' },
    employees: { type: 'array', items: { $ref: 'Employee' } }
  }
}

export const jobValidator = getValidator(jobSchema, dataValidator)
export const jobResolver = resolve({})

export const jobExternalResolver = resolve({})

// Schema for creating new data
export const jobDataSchema = {
  $id: 'JobData',
  type: 'object',
  additionalProperties: false,
  required: ['jobname'],
  properties: {
    ...jobSchema.properties
  }
}
export const jobDataValidator = getValidator(jobDataSchema, dataValidator)
export const jobDataResolver = resolve({})

// Schema for updating existing data
export const jobPatchSchema = {
  $id: 'JobPatch',
  type: 'object',
  additionalProperties: false,
  required: [],
  properties: {
    ...jobSchema.properties
  }
}
export const jobPatchValidator = getValidator(jobPatchSchema, dataValidator)
export const jobPatchResolver = resolve({})

// Schema for allowed query properties
export const jobQuerySchema = {
  $id: 'JobQuery',
  type: 'object',
  additionalProperties: false,
  properties: {
    ...querySyntax(jobSchema.properties)
  }
}
export const jobQueryValidator = getValidator(jobQuerySchema, queryValidator)
export const jobQueryResolver = resolve({})

and this is my employee.schema.js

// For more information about this file see https://dove.feathersjs.com/guides/cli/service.schemas.html
import { resolve, getValidator, querySyntax } from '@feathersjs/schema'
import { ObjectIdSchema } from '@feathersjs/schema'
import { dataValidator, queryValidator } from '../../validators.js'

// Main data model schema
export const employeeSchema = {
  $id: 'Employee',
  type: 'object',
  additionalProperties: false,
  required: ['employeeName'],
  properties: {
    _id: ObjectIdSchema(),
    employeeName: { type: 'string' },
    employeeStatus: { type: 'string' },
    employeePhoto: { type: 'string' },
    employeeTel: { type: 'string' },
    employeeQr: { type: 'string' },
    employeeOrder: { type: 'string' },
    employeeState: { type: 'string' },
    login: { type: 'string' },
    job: { type: 'array', items: { $ref: 'Job' } }
    // office: { type: 'string', $ref: 'Office' },
    // department: { type: 'string', $ref: 'Department' }
  }
}
export const employeeValidator = getValidator(employeeSchema, dataValidator)
export const employeeResolver = resolve({})

export const employeeExternalResolver = resolve({})

// Schema for creating new data
export const employeeDataSchema = {
  $id: 'EmployeeData',
  type: 'object',
  additionalProperties: false,
  required: ['employeeName'],
  properties: {
    ...employeeSchema.properties
  }
}
export const employeeDataValidator = getValidator(employeeDataSchema, dataValidator)
export const employeeDataResolver = resolve({})

// Schema for updating existing data
export const employeePatchSchema = {
  $id: 'EmployeePatch',
  type: 'object',
  additionalProperties: false,
  required: [],
  properties: {
    ...employeeSchema.properties
  }
}
export const employeePatchValidator = getValidator(employeePatchSchema, dataValidator)
export const employeePatchResolver = resolve({})

// Schema for allowed query properties
export const employeeQuerySchema = {
  $id: 'EmployeeQuery',
  type: 'object',
  additionalProperties: false,
  properties: {
    ...querySyntax(employeeSchema.properties)
  }
}
export const employeeQueryValidator = getValidator(employeeQuerySchema, queryValidator)
export const employeeQueryResolver = resolve({})

Im getting an error:

throw new ref_error_1.default(it.opts.uriResolver, baseId, $ref);
                  ^

MissingRefError: can't resolve reference Employee from id Job
  missingRef: 'Employee',missingSchema: 'Employee'

I'm very upset, because I did it like in documentation, GPT didnt help as well and I'm pretty much frustrated... anyone can explain me where is the problem?


Solution

  • The problem for this error is usually in the query schema and validators because they don't automatically know about references (since you can't query for references). The two options are

    1. Omitting the references from the properties:
    const { office, department, ...employeQueryProperties } = employeeSchema.properties
    
    // Schema for allowed query properties
    export const employeeQuerySchema = {
      $id: 'EmployeeQuery',
      type: 'object',
      additionalProperties: false,
      properties: {
        ...querySyntax(employeQueryProperties)
      }
    }
    export const employeeQueryValidator = getValidator(employeeQuerySchema, queryValidator)
    export const employeeQueryResolver = resolve({})
    
    1. Adding the references to the query validator:
    queryValidator.addSchema(employeeSchema)
    

    Option 2) is easier but might allow making queries that fail.