Reputation: 34367
I have an "Assignments" MongoDB collection with documents containing a scoring function. I want to store this scoring function in the Assignment document as the scoring logic may change over time as new assignments are created:
{
_id: "assignment1",
question: "Number between 1 and 10",
scoringFunction: function (value) { value * 2 }
}
When a user completes an assignment a new document in the "Events" collection is inserted:
{
_id: "event1",
answer: "4",
score: "8"
}
I can insert the above Assignment document into my Assignments collection, however when I attempt to retrieve the scoringFunction
it's no longer a function it's an object.
Some debugging code:
const assignment = Assignments.findOne({ _id: "test" })
console.log(assignment.scoringFunction)
Debugging code output:
Code {
_bsontype: 'Code',
code: 'function (value) { value * 2 }',
scope: undefined
}
How can I decode this object back into a JavaScript function which can be called with parameters to calculate the score?
Upvotes: 1
Views: 1676
Reputation: 34367
Ideally — from a data security perspective — don’t store executable code in your data.
In the case that a hacker (or user) is able to alter this function in your database, they could compromise your data or break your app if the function doesn’t work correctly.
I'm going to store the name of the scoring function in the assignment.
{
_id: "assignment1",
question: "Number between 1 and 10",
scoringFunction: "scoreAssignment1"
}
const scoreAssignment1 = (value) => value * 2
const assignment = Assignments.findOne({ _id: "test"})
console.log(Meteor.call(assignment.scoringFunction, 2))
// output: 4
Store the body of the scoringFunction
in a string, then use new Function()
to create a function from the desired parameters and function body string.
{
_id: "assignment1",
question: "Number between 1 and 10",
scoringFunction: "value * 2"
}
const assignment = Assignments.findOne({ _id: "test"})
const scoringFunction = new Function('value', assignment.scoringFunction)
console.log(scoringFunction(2))
// output: 4
Upvotes: 0