Avatar of Bruce Gust
Bruce Gust
Flag for United States of America

asked on 

What is Discriminator and Why is is Problem in this Case?

Here's what I understand about "Discriminators..."

http://brucegust.com/adm/bSmart/#review_7

Basically, it's similar to a Foreign Key if I were to try and describe it in the context of a relational database dynamic.

I'm getting an error when I insert a document into a collection that reads like this:

error":true,"msg":"Discriminator with name \"call\" already exists","data":[]}

From what I understand, a "Discriminator" needs to be unique, but I'm not sure I understand that concept let alone how it's going to work in this particular scenario.

I'm trying to add a note. A note is a type of activity. "activity" is related to "company" and I'm going to post the relevant models and code below.

How to fix the error?

Company Schema

const mongoose = require('mongoose');

const { Schema } = mongoose;

const ActivitySchema = new Schema(
  {
    type: {
      type: String,
      required: true,
      enum: [
        'call',
        'visit',
        'reminder',
        'event',
        'Company created',
        'Company updated',
        'Company deleted',
        'Broker info added',
        'Broker info updated',
        'Contact added',
        'Contact updated',
        'Address added',
        'Address updated',
        'Proposal created',
        'Proposal updated',
        'Converted to company',
        'Target selected',
        'Target ignored',
        'Owner change',
        'Proposal assigned',
        'File attached',
        'File removed',
        'User added',
        'User deleted',
        'Service line added',
        'Service line deleted',
        'Swimlane added',
        'Swimlane removed',
        'Custom Fields Updated'
      ]
    },
    company: {
      type: Schema.Types.ObjectId,
      required: true,
      ref: 'Company'
    },
    proposal: {
      type: Schema.Types.ObjectId,
      ref: 'Proposal'
    },
    pipeline: {
      type: Schema.Types.ObjectId, // for tracking activity on each pipeline stage.
      ref: 'PipelineColumn'
    },
    user: {
      type: Schema.Types.ObjectId,
      ref: 'User'
    },
    date: {
      type: Date,
      default: Date.now
    },
    meta: {
      type: Schema.Types.Mixed
    },
    account: {
      type: Schema.Types.ObjectId,
      default: () => global._user.account._id
    },
    active: { type: Boolean, default: true }
  },
  { discriminatorKey: 'type', collation: 'activities' }
);
// removed strict:false and added discriminatorKey for meta.start, meta.end, meta.date fields for type=event/call/note/reminder

module.exports = ActivitySchema;

Open in new window


Company Schema

const mongoose = require('mongoose');

require('../lib/mongoose-types/Email');
require('../lib/mongoose-types/PostalCode');
const mongooseTypePhone = require('mongoose-type-phone');

const { Schema, SchemaTypes } = mongoose;

const CompanySchema = new Schema({
  name: {
    type: String,
    required: true
  },
  status: {
    type: String,
    enum: ['info', 'warning', 'danger', 'success']
  },
  market: {
    type: Schema.Types.ObjectId,
    ref: 'Prospect'
  },
  account: {
    type: Schema.Types.ObjectId,
    default: () => global._user.account._id
  },
  owner: {
    type: Schema.Types.ObjectId,
    ref: 'User'
  },
  files: [
    {
      key: {
        type: String,
        required: true
      },
      name: {
        type: String,
        required: true
      },
      url: {
        type: String,
        required: true
      },
      date: {
        type: Date,
        required: true,
        default: Date.now
      }
    }
  ],
  meta: {
    fundingStatus: {
      type: String,
      required: true,
      enum: ['Unknown', 'Fully', 'Mixed', 'Self'],
      default: 'Unknown'
    },
    ftes: {
      type: Number,
      default: 0
    },
    premium: {
      type: Number,
      default: 0
    },
    revenue: {
      type: Number,
      default: 0
    },
    fteGrouping: {
      type: String,
      enum: [
        'Unknown',
        '50-99',
        '100-499',
        '500-999',
        '1000-4999',
        '> or = 5000'
      ],
      default: 'Unknown'
    },
    industry: String,
    premiumPerFte: {
      type: Number,
      default: 0
    },
    brokerCommissionTotal: {
      type: Number,
      default: 0
    },
    brokerFeesTotal: {
      type: Number,
      default: 0
    },
    ein: {
      type: String
    },
    fax: {
      type: SchemaTypes.Phone,
      defaultRegion: 'US',
      phoneNumberFormat: mongooseTypePhone.PhoneNumberFormat.INTERNATIONAL,
      required: false,
      allowBlank: true
    },
    companyUrl: {
      type: String
    },
    businessDescription: {
      type: String
    },
    SIC: {
      type: String
    },
    SICDescription: {
      type: String
    },
    source: {
      type: String
    }
  },
  brokers: [
    {
      _id: false,
      name: {
        type: String
      },
      normalized: {
        type: String
      },
      street: {
        type: String
      },
      street2: {
        type: String
      },
      city: {
        type: String
      },
      state: {
        type: String,
        match: /^[A-Z]{2}/,
        uppercase: true
      },
      postal: {
        type: SchemaTypes.PostalCode,
        required: false,
        allowBlank: true
      },
      commission: {
        type: Number,
        default: 0
      },
      fees: {
        type: Number,
        default: 0
      },
      feesText: {
        type: String
      }
    }
  ],
  dates: {
    created: {
      type: Date,
      default: Date.now
    },
    updated: Date,
    assigned: Date
  },
  clientMessage: {
    type: String
  },
  active: {
    type: Boolean,
    required: true,
    default: true
  },
  addresses: [
    {
      street: {
        type: String,
        required: true
      },
      street2: {
        type: String,
        required: false
      },
      city: {
        type: String,
        required: true
      },
      state: {
        type: String,
        required: true,
        trim: true,
        uppercase: true,
        match: /^[A-Z]{2}/
      },
      postal: {
        type: SchemaTypes.PostalCode,
        required: true
      },
      county: String,
      country: {
        type: String,
        default: 'US',
        uppercase: true,
        match: /^[A-Z]{2}/
      },
      hash: String,
      formatted: String,
      nonGeo: String,
      default: {
        type: Boolean,
        default: false
      },
      active: {
        type: Boolean,
        default: true
      },
      error_message: String
    }
  ],
  contacts: [
    {
      name: {
        type: String,
        required: true
      },
      email: {
        type: SchemaTypes.Email,
        required: false
      },
      phone: {
        type: SchemaTypes.Phone,
        defaultRegion: 'US',
        phoneNumberFormat: mongooseTypePhone.PhoneNumberFormat.INTERNATIONAL,
        required: false
      },
      default: {
        type: Boolean,
        default: false
      },
      active: {
        type: Boolean,
        default: true
      }
    }
  ],
  deleted: Boolean,
  pipeline: {
    type: Schema.Types.ObjectId
  },
  _pipelineDate: {
    type: Date
  },
  source: {
    type: String
  },
  clientImport: {
    type: Schema.Types.ObjectId
  },
  ACK_ID: {
    type: String,
    index: true
  },
  customFields: {
    type: Schema.Types.Mixed
  }
});

module.exports = CompanySchema;

Open in new window


Code I'm using to insert an activity:

router.post(
  '/companies/add-activity',
  celebrate({
    [Segments.BODY]: Joi.object().keys({
      type: Joi.string().required(),
      company: Joi.array().required(),
      activityType: Joi.string().optional()
    })
  }),
  async (req, res) => {
    if (
      typeof req.body.activityType === 'undefined' ||
      req.body.activityType === ''
    ) {
      req.body.activityType = req.body.type;
    } else {
      // set the activity type as the main type - I added this in after a request to
      // combine several types
      req.body.type = req.body.activityType;
    }

    // validate the content based on the type
    try {
      if (Array.isArray(req.body.company)) {
        const ids = [];
        const companies = req.body.company.filter(
          (elem, pos) => req.body.company.indexOf(elem) === pos
        ); // Remove duplicates
        let counter = companies.length;
        for (let i = 0; i < companies.length; i += 1) {
          try {
            counter -= 1;
            const _companyId = companies[i];
            if (_companyId === 'bulk') {
              ids.push('_0');
              if (counter === 0) {
                res.send(Company.success({ id: companies[0] }));
              }
            } else {
              // eslint-disable-next-line no-await-in-loop
              const id = await Company.addActivity(
                _companyId,
                req.body.type,
                req.body
              );
              ids.push(id);
              if (counter === 0) {
                res.send(Company.success({ id: companies[0] }));
              }
            }
          } catch (e) {
            res.send(Company.error(e));
          }
        }
      } else {
        const id = await Company.addActivity(
          req.body.company,
          req.body.type,
          req.body
        );
        res.send(Company.success({ id }));
      }
    } catch (err) {
      res.send(Company.error(err));
    }
  }
);

Open in new window


What do I need to change and why?

Thanks!
Node.jsMongoDBDatabasesJavaScriptNoSQL Databases

Avatar of undefined
Last Comment
Bruce Gust

8/22/2022 - Mon