Q: How to override property lookup logic (support fields with dots)
Hi! I wonder is it possible to override the logic of fields navigation. For example, if I want instead of normal navigation of nested object also support fields with dots in their names. Here's an example, two objects, obj1 - with a nested value, obj2 - with a dot in a field's name. I'd expect the expression "main.temp" works in both cases.
let obj1 = { main: { temp: 280 } };
let obj2 = { "main.temp": 280 };
let expr = 'main.temp > 273';
Works:
console.log(math.evaluate(expr, obj1));
Doesn't (throws 'Undefined symbol main'):
console.log(math.evaluate(expr, obj2));
two nested objects is really different from a key with a dot in the name, and it can lead to ambiguous cases when you want to resolve nested objects. Like here:
let obj3 = {
main: {
temp: 280
},
'main.temp': 260
};
So what would you expect to get when evaluating let expr = 'main.temp > 273'; in this case?
What you maybe could do is pre-process your scope: replace objects with a dot in the name with nested objects. I.e. replace obj2 with obj in your example.
Well, yeah, agree it's not very straightforward, that's because I'm asking about customization and don't expect the lib supports this case by default.
In my case I have several data feeds (arrays of object, possibly nested), that I want to join. For this, I flatten them into array-like maps, like this:
// input
feed1: [
{ city: {name: "city1", id: 1}, main: { temp: 280 }},
{ city: {name: "city2" id: 2}, main: { temp: 281 }}
]
// output
feed1: [
{
"city.name": "city1",
"city.id": 1,
"main.temp": 280
},
{
"city.name": "city2",
"city.id": 2,
"main.temp": 281
}
I'm doing this as I have another feed with a foreign key:
feed2: [
{ "city_id": 1, "some_column": "some_value1" },
{ "city_id": 2, "some_column": "some_value2" }
]
and a result feed will be:
result: [
{
"city.name": "city1",
"city.id": 1,
"main.temp": 280,
"some_column": "some_value1"
}, // etc
]
so I don't have any ambiguity, the expr 'main.temp > 273' will address a "column" (technically a field).
I understand that there're workarounds, e.g. I can possible unwind it back to nested objects:
[
{
feed1: { city: { name: "city", id: 1}, main: {temp: 280}, feed2: { some_column: "some_value1"} }, //etc
// or
{ city: { name: "city", id: 1}, main: {temp: 280}, some_column: "some_value1"}, //etc
}
]
or try to join them without flattening. But there could be other reason for flattening so I wanted to investigate all my options.
I understand your use case. I agree that this is a quite specific use case so it makes sense to keep this as a solution (could be a plugin or simply a snippet) separate from mathjs.
I think the most straightforward solution is what you're proposing: do some flattening and merging beforehand yourself to mold the data in the structure that you want to have to expose it inside the expression editor.
The solution I found for a similar problem was to wrap the object like this:
math.evaluate(`data['main.temp'] > 273`, { data })