Extracting default value from a Mongo Collection


#1

I’m using autoforms, collection2 and SimpleSchema. I’d like to segregate the population of default values so that they can be changed at a later point in time directly in mongo rather than hard-coding them in the schema itself. I tried the below approach but it doesn’t seem to be working. The console log says “undefined”. How do I go about this?

Schema:

Defaults = new Mongo.Collection('Defaults');
[...]

  "lock-time.interval":{
        type: Number,
        decimal: false,
        min: 30, max:3600,
        defaultValue: function() {
            **console.log(
                Defaults.findOne({},{_id:0,"lock-time-interval":1}));
            return Defaults.findOne(Defaults.findOne({},{_id:0,"lock-time-interval":1}));**
            
        }
    }
[...]

Mongo Collection:

    meteor:PRIMARY> db.Defaults.findOne({});
    {
    	"_id" : ObjectId("5768f728708012bb60501f0b"),
    	"lock-time-interval" : 300
    }
    meteor:PRIMARY>

--------------------UPDATE-----------------------

I also tried the below after restructuring the mongo record. the console is returning something like an array object. Upon further reading, it does make sense as it’s mentioned that an array will be returned. How exactly do I extract the needed value from the array?

 "lock-time.interval":{
        type: Number,
        decimal: false,
        min: 30, max:3600,
         defaultValue: function() {
            console.log(
            Defaults.find().map(function(c){
                return {value: c.value};
            }))
            
        }
    },

MongoDB

meteor:PRIMARY> db.Defaults.findOne({});
{
	"_id" : ObjectId("57690508708012bb60501f0d"),
	"name" : "lock-time-interval",
	"value" : 300
}

[ + @hwillson ]


#2

Are you sure your Default Collection is subscribed to (on the client), and data is available, before your schema defaultValue function is called? Otherwise querying the Default Collection won’t return any data. It sounds like in your first example the Collection wasn’t ready when the console.log was run, but in your second example if you’re getting data back then it is ready.

If you just want to return one value in your second example, use the findOne approach you have in your first example. If you’re seeing data returned in your second example, then something else has changed in your app to make the Collection data available when defaultValue is called, so findOne should also work.


#3

Magic! I had forgotten to pub sub. It works now. While we’re on the topic of pub sub, please let me know if my approach is right. Because I get the feeling i’m declaring the same things over and over again in multiple places.

The collection name is Defaults.

server/main.js

Defaults = new Mongo.Collection('Defaults');
Meteor.publish("DefaultsPublication", function publishFunction(){
    return Defaults.find();
});

client/main.js

Defaults = new Mongo.Collection('Defaults');
Meteor.subscribe("DefaultsPublication");

both/collections/someschema.js

//Default = new Mongo.Collection('Default'); --> I declare it here as well. Is this required? Commenting it out does no harm either.


#4

The way you have it will work, but you could simplify this a bit by switching things around. Remove the Defaults = new Mongo.Collection('Defaults'); declaration from both /client/main.js and /server/main.js, and instead keep it in your /both/collections/someschema.js. The contents of your both directory will be loaded first due to Meteor’s eager file loading rules (both comes before the other directories alphabetically).

One thing to mention - you might want to consider moving away from using Meteor’s eager loading, and instead leverage the newer ES2015 /imports lazy loading approach. Check out the ES2015 modules section of the Guide for more info.


#5

Thanks for the insight! I shall dive into this now.

Falling back to the original issue I had, I’m trying the same with radio buttons. My query seems correct, however, I’m unable to select the radios by default. Do you see anything off with the below?

“lock-time.enable”:{

type: String,

//defaultValue: “yes”,

defaultValue:

function () {

return Defaults.find({“schemaName”:“group_schema”, “name”:“lock-time-enable”},{value:1,_id:0}).map(function© {return c.value;})[0];

},

autoform: {

type: “select-radio-inline”,

options: function(){

return [

{label: “Yes”,value: “yes”},

{label: “No”,value: “no”}

];

}

}

},

DB Contents:

meteor:PRIMARY> db.Defaults.find({“name”:“lock-time-enable”})

{ “_id” : ObjectId(“57693bf7708012bb60501f17”), “schemaName” : “group_schema”, “name” : “lock-time-enable”, “value” : “yes” }

meteor:PRIMARY>

Map returns an array with [“Yes”] and so I used [0] to pick up the first element in the array. While the DB returns the results as expected, when I try implement the same query in the schema, my radio buttons seem dead. The default value doesn’t get applied.

meteor:PRIMARY> db.Defaults.find({“schemaName”:“group_schema”, “name”:“lock-time-enable”},{value:1,_id:0}).map(function©{return c.value;})[0]

yes

meteor:PRIMARY> db.Defaults.find({“schemaName”:“group_schema”, “name”:“lock-time-enable”},{value:1,_id:0}).map(function©{return c.value;})

[ “yes” ]

Please disregard my above blurred query, i figured out my mistake. The return function only works when it’s wrapped within the autoform: {}. it doesn’t work directly at the schema level.

This worked:

  "lock-time.enable":{
        type: String,
        autoform: {
            type: "select-radio-inline",
            options: function(){
                return [
                    {label: "Yes",value: "yes"},
                    {label: "No",value: "no"}
                ];
            },
            defaultValue: function () {
           return Defaults.find({"schemaName":"group_schema", "name":"lock-time-enable"},{value:1,_id:0}).map(function(c) {return c.value;})[0];
        }
        }
    }

#6
const defaultValue = MyCollection.simpleSchema().schema('whatever-field').defaultValue;