function applyVirtualsToDoc(schema, obj, virtuals) {
  if (obj == null || typeof obj !== 'object') {
    return;
  }
  if (Array.isArray(obj)) {
    for (const el of obj) {
      applyVirtualsToDoc(schema, el, virtuals);
    }
    return;
  }

  if (schema.discriminators && Object.keys(schema.discriminators).length > 0) {
    for (const discriminatorKey of Object.keys(schema.discriminators)) {
      const discriminator = schema.discriminators[discriminatorKey];
      const key = discriminator.discriminatorMapping.key;
      const value = discriminator.discriminatorMapping.value;
      if (obj[key] == value) {
        schema = discriminator;
        break;
      }
    }
  }

  if (virtuals == null) {
    virtuals = Object.keys(schema.virtuals);
  }
  for (const virtual of virtuals) {
    if (schema.virtuals[virtual] == null) {
      continue;
    }
    const virtualType = schema.virtuals[virtual];
    const sp = Array.isArray(virtual)
      ? virtual
      : virtual.indexOf('.') === -1
        ? [virtual]
        : virtual.split('.');
    let cur = obj;
    for (let i = 0; i < sp.length - 1; ++i) {
      cur[sp[i]] = sp[i] in cur ? cur[sp[i]] : {};
      cur = cur[sp[i]];
    }
    let val = virtualType.applyGetters(cur[sp[sp.length - 1]], obj);
    const isPopulateVirtual =
      virtualType.options && (virtualType.options.ref || virtualType.options.refPath);
    if (isPopulateVirtual && val === undefined) {
      if (virtualType.options.justOne) {
        val = null;
      } else {
        val = [];
      }
    }
    cur[sp[sp.length - 1]] = val;
  }
}
Apply virtuals to a given document. Does not apply virtuals to subdocuments: use `applyVirtualsToChildren` instead

@param {Schema} schema
@param {Object} doc
@param {Array<String>} [virtuals] optional whitelist of virtuals to apply
@returns