Search code examples
node.jsmongodbmongoosenunjucks

Why Does Looping Through a Mongoose Object Display Metadata?


Why does looping through a mongoose object with nunjucks display metadata?

I am using mongodb and nunjucks in an app I am writing.

I am trying to iterate through a model called persona, but doing so displays mongoose metadata associated with the record.

If I simply display the persona variable by writing {{persona}}.

My output is as follows. Just the keys/values defined in my schema.

{ _id: 582f186df1f05603132090d5, name: 'Alex', name_lower: 'alex', __v: 0, 
meta: { validated: null, contributors: 'Research Team', sources: '4 Interviews' }, 
pain_points: { points: 'Debugging' }, 
ideal_day: { responsibilities: 'Coding websites.', goals: 'Finish the research site.', joys: 'Good code, Good food.', hobbies: 'Dance, Hiking, Eating' }, 
environment: { workspace: 'Desk', tools: 'Atom, Sketch', info_from: null, info_to: null, coworkers_relationship: null, technology_relationship: null }, 
basic_info: { jobtitle: 'FED', experience: '2', education: 'CS', company: '' } }

However, if I loop through the persona


    {% for name, item in persona %}
        {{ name }} : {{ item }}
    {% endfor %}

In addition to displaying the keys in my schema, all mongoose metadata associated with the record will also be displayed. I would like to understand why different information is displayed when I am looping over the object.


    $__
    isNew
    errors
    _doc
    $__original_save
    save
    _pres
    _posts
    $__original_validate
    validate
    $__original_remove
    remove
    db
    discriminators
    __v
    id
    _id
    meta
    pain_points
    ideal_day
    environment
    basic_info
    updated_at
    created_at
    name_lower
    name
    schema
    collection
    $__handleSave
    $__save
    $__delta
    $__version
    increment
    $__where

I was able to fix this problem by using Mongoose's lean(), but still don't understand why I experienced this behavior.


Solution

  • When you call {{persona}} then result is persona.toString().
    If object doesn't have override method toString then result will be [Object object] (by default toString method).

    When you use loop {% for key, value in persona %} then it's equals to

    for(var key in obj)
      print(key + ' - ' + obj[key]);
    

    This code prints all object properties and methods.

    To exclude methods you must use next loop

    for(var key in obj)
      if (typeof(obj) != 'function') // or obj.hasOwnProperty(key)
          print(key + ' ' + obj[key]);
    

    So, to avoid your problem you must "clear" data before pass it to nunjucks or before output.
    You can do it define custom filter

    var env = nunjucks.configure(...
    
    env.addFilter('lean', function(obj) {
        var res = {};
        for(var key in obj)
            if (typeof(obj) != 'function') // or obj.hasOwnProperty(key)
               res[key] = obj[key];
        return res;
    });
    ...
    {% for key, value in persona | lean %}
    {{key}} - {{value}}
    {% endfor %}