Randy Hall
Randy Hall

Reputation: 8167

Mongoose schema field names and types with subdocs

I'm building an object of field names and their types from my schema:

var ret = {};
ThisCollection.schema.eachPath(function(path) {
  ret[path] = ThisCollection.schema.path(path).instance;
});

Which is great unless there's a nested array in the schema. I can't seem to figure out how to access the subdocument and its fields' types. I've tried:

ThisCollection.schema.path("dot.notation").instance

within a recursive function building out the dot notation name of a deeper path. This does not appear to work.

Example schema:

 var Person = new Schema({
    person_code: String, 
    person_name: String, 
    location_details:[{
        location_name: String,
        location_code: String
    }]
});

To be clear, I'm looking for my return object to match my schema in structure as well, so that nested schemas are nested objects in my return object, something like:

{
    person_code: String,
    person_name: String,
    location_details:{
        location_name: String,
        location_code: String
    }
}

Upvotes: 4

Views: 6191

Answers (4)

dna4php
dna4php

Reputation: 56

If you are looking to get the field names in a schema then this is a simple way to do it:

const schema = [dbname].schema; 
const fieldNames = Object.keys(schema.obj);

This will give you an array of field names. The schema.obj also specifies the field type.

Upvotes: 0

Ankit Kumar
Ankit Kumar

Reputation: 1795

you can get the type of property of a subdoc by

[Collection].schema.paths.[sub-doc].schema.paths.[sub-doc-property].instance   // it will give dataytpe

you can nest it as how many nested sub-doc you have

for your collection you can use

ThisCollection.schema.paths.location_details.schema.paths.location_name.instance   // String

_

/**
* @param {Object} coll       - Collection
* @param {string} props      - properties, eg. "abc", "abc.xyz", upto n number of nested dot notation
*/
function getType(coll, props) {
    return props.split('.').reduce(function (p, n, index, array) {
        if (index < array.length - 1) {
            return p.schema.paths[n];
        }
        return p.schema.paths[n].instance;
    }, coll);
}

var type = getType(ThisCollection, "location_details.location_name");
console.log(type); // String

Upvotes: 1

JohnnyHK
JohnnyHK

Reputation: 312139

The simplest solution may be to simply save off the schema definition object you're using to create your schema:

var personSchemaDef = {
    person_code: String,
    person_name: String,
    location_details: [{
        location_name: String,
        location_code: String
    }]
};
var personSchema = new Schema(personSchemaDef);
var Person = mongoose.model('person', personSchema, 'people');

But you can also get the hierarchical details of the schema from the tree property of the schema:

console.log(Person.schema.tree)

Output:

{ person_code: [Function: String],
  person_name: [Function: String],
  location_details:
   [ { location_code: [Function: String],
       location_name: [Function: String] } ],
  _id:
   { type: { [Function: ObjectId] schemaName: 'ObjectId' },
     auto: true },
  id:
   VirtualType {
     path: 'id',
     getters: [ [Function: idGetter] ],
     setters: [],
     options: {} },
  __v: [Function: Number] }

Upvotes: 4

chridam
chridam

Reputation: 103475

The key here is to create an object from the paths, in particular the paths with the dot notation string. You can use the following method that sets an object given the property and value;

var ret = {};
var setObject = function(name, schema, context) {
    var parts = name.split("."), 
        p = parts.pop(),
        value = schema.path(p).instance;
    for(var i=0, j; context && (j=parts[i]); i++){
        context = (j in context ? context[j] : context[j]={});
    }        
    return context && p ? (context[p]=value) : undefined; // Object
}

ThisCollection.schema.eachPath(function(path) {         
    setObject(path, ThisCollection.schema, ret);        
});

Upvotes: 1

Related Questions