Freemarker: iterate over nested array - arrays

I want to iterate over a nested array I created in Freemarker but can't figure out how to print each value.
The array var
<#assign filters = [
{ "p1" : [ "performance" ] },
{ "p2" : [ "nav" ] },
{ "p3" : [ "quarterly" ] },
{ "f1" : [ "50496", "50497", "50501" ]},
{ "f2" : [ "51202", "51196", "51203", "51246", "51207", "51260" ]},
{ "f3" : [ "50504", "50505", "50506" ]},
{ "f4" : [ "50507", "50508", "50509", "50510", "50512" ]}
]>
Iterating over the array
<#list filters as filter>
${filter}'<#sep>,
</#list>
I want to create an output that looks like this:
$.plugin.function({
p1: 'performance',
p2: 'nav',
p3: 'quarterly',
fi: '50496' + '|' + '50497' + '|' + '50501',
f2: etc....
});
My error is this:
For "${...}" content: Expected a string or something automatically
convertible to string (number, date or boolean),
but this has evaluated to an extended_hash
Any suggestions?

The issue is that Freemarker doesn't have a way to convert filter (a hash) into a string. I think that you want the keys function. Where you now have
${filter}'<#sep>,
You'd instead call
<#list filter?keys as prop>
...
</#list>
and iterate over those keys. In your example there would only be one key per filter and the value
filter[prop]
would be the array, that you'd also have to iterate over.
See Freemarker iterating over hashmap keys

I think you overcomplicate the data structure by using a list of hash-es. Instead, just use a hash:
<#assign filters = {
"p1" : [ "performance" ],
"p2" : [ "nav" ],
"p3" : [ "quarterly" ],
"f1" : [ "50496", "50497", "50501" ],
"f2" : [ "51202", "51196", "51203", "51246", "51207", "51260" ],
"f3" : [ "50504", "50505", "50506" ],
"f4" : [ "50507", "50508", "50509", "50510", "50512" ]
}>
<#list filters?keys as name>
${name}: <#list filters[name] as value>'${value}'<#sep> + '|' + </#list><#sep>,
</#list>
(Another possibility would be a list of lists, but that's less natural.)

Related

mongodb - Get one array from two arrays in collection

In my mongodb collection, I have sometimes two, sometimes one and sometimes null arrays on a document. Now I'd like to get one array over the whole collection with the values of these arrays.
The document looks like this:
{
"title" : "myDocument",
"listOne" : [
"valueOne",
"valueTwo"
],
"listTwo" : [
"abc",
"qwer"
]
},
{
"title" : "myDocumentTwo",
"listTwo" : [
"321"
]
},
{
"title" : "myDocumentAlpha",
"listOne" : [
"alpha",
"beta"
]
},
{
"title" : "myDocumentbeta"
}
And I expect the following output:
"combinedList" : [
"valueOne",
"valueTwo",
"abc",
"qwer",
"321",
"alpha",
"beta"
]
It's like every possible value from these twos array out of every document in this collection.
You can do this using aggregate and $concatArrays
db.collection.aggregate([
{
$project: {
combinedList: {
$concatArrays: [{$ifNull: ["$listOne", []]}, {$ifNull: ["$listTwo", []]}]
}
}
},
{ $unwind: "$combinedList" },
{ $group: { _id: null, combinedList: { $addToSet: "$combinedList"}}},
{ $project: { _id: 0, combinedList: 1 }}
])

In mongo db, how can I set a value in an array of arrays without knowing the index?

In Mongo DB, how can I set values in an array of arrays when the index cannot be assumed?
For example, how can I set the IdleShutdown value to "2" (instead of "10") in this blob below?
What would the command look like to correctly find the item in the list and set the value without any assumptions that the current index will stay the same? I also cannot assume any values for the second item in the list (eg, "10" could become any value)
> db.EventPluginSettingsCollection.findOne({"_id": "spot"})
{
"_id" : "spot",
"LastWriteTime" : ISODate("2019-12-16T11:04:30.499Z"),
"Name" : "Spot",
"PluginEnabled" : 1,
"DebugLogging" : false,
"Icon" : null,
"Limits" : [ ],
"DlInit" : [
[
"State",
"Disabled"
],
[
"Config",
"{}"
],
[
"IdleShutdown",
"10"
],
[
"StaggerInstances",
"50"
],
[
"PreJobTaskMode",
"Conservative"
],
[
"AWSInstanceStatus",
"Disabled"
]
],
"Meta" : {
}
}
I understand I could replace the whole blob, and I could also use individual indexes for each item, but none of these approaches are future proof should the number of items in the list change in the future.
MongoDB 3.6 introduced the filtered positional operator array update operator, $[ < identifier> ], for these types of operations. Updates using this syntax will only update elements of an array that match a specified array filter.
For example:
> db.foo.update(
... { "_id" : "spot" },
... {
... "$set" : {
... // only updates array elements matching the filter below
... "DlInit.$[element]" : [ "IdleShutdown", "2"]
... }
... },
... {
... "arrayFilters": [
... // Search for DlInit array elements that are the specified array
... { "element.0" : "IdleShutdown" }
... ]
... }
... )
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.foo.find().pretty()
{
"_id" : "spot",
"LastWriteTime" : ISODate("2019-12-16T11:04:30.499Z"),
"Name" : "Spot",
"PluginEnabled" : 1,
"DebugLogging" : false,
"Icon" : null,
"Limits" : [ ],
"DlInit" : [
[
"State",
"Disabled"
],
[
"Config",
"{}"
],
[
"IdleShutdown",
"2"
],
[
"StaggerInstances",
"50"
],
[
"PreJobTaskMode",
"Conservative"
],
[
"AWSInstanceStatus",
"Disabled"
]
],
"Meta" : {
}
}

Multiple, mostly empty ID arrays returned

I'm new to node.js and admittedly I'm probably trying to learn the hard way but I use the following code to parse json looking for the id when the corresponding name contains the uuid. The uuid gets passed from a different function.
var arrFound = Object.values(json).filter(function(obj) {
return obj.id && obj.name.includes(uuid);
}).map(function(obj) {
return obj.id;
});
console.log (arrFound); // array of matched id values
I expect this to return something like [ 'local-1517085058363' ].
Instead I get this:
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[ 'local-1517085058363' ]
[ 'local-1517085058363' ]
[ 'local-1517085058363' ]
[ 'local-1517085058363' ]
[ 'local-1517085058363' ]
[ 'local-1517085058363' ]
[ 'local-1517085058363' ]
[ 'local-1517085058363' ]
[ 'local-1517085058363' ]
The json comes from the Spark HistoryServer API(http://127.0.0.1:18080/api/v1/applications), although it's just JSON so shouldn't matter where it comes from. Here is a sample:
[{
"id" : "local-1517085058363",
"name" : "TeraGen (5MB) 6e722700-0397-11e8-ae84-b54a3ebb27aa",
"attempts" : [ {
"startTime" : "2018-01-27T19:22:37.513GMT",
"endTime" : "2018-01-27T19:22:43.253GMT",
"lastUpdated" : "2018-01-27T19:22:43.000GMT",
"duration" : 5740,
"sparkUser" : "paulcarron",
"completed" : true,
"endTimeEpoch" : 1517080963253,
"startTimeEpoch" : 1517080957513,
"lastUpdatedEpoch" : 1517080963000
} ]
} ]
Also, I'm running my code on Gulp. I'm not sure if that will make any difference.
How do I fix this so I only return one single id?
There was multiple arrays so that explains where they came from. I used a reduce() to get the object I was looking for.

mongodb, how to find in array other array

I need some help. I am trying to find an array in another array.
Records:
{
"_id" : ObjectId("56b7e6966213e8d142ef55b7"),
"users" : [
ObjectId("56b0e547a838b5a45b4d0100"), // 0
ObjectId("56a7e16e37e5adf32b97cc3d") // 1
]
},
{
"_id" : ObjectId("56b7e6966213e8d142ef55b7"),
"users" : [
ObjectId("56b0e547a838b5a45b4d0100"),
ObjectId("56a7e16e37e5adf32b97cc3d"),
ObjectId("56b7e6b96213e8d142ef55b8")
]
}
I'm trying to find only first record "_id" : ObjectId("56b7e6966213e8d142ef55b7"),
I'm using query:
db.collection.find({"users" : { $in: [
ObjectId("56b0e547a838b5a45b4d0100"),
ObjectId("56a7e16e37e5adf32b97cc3d")
]}})
or
db.collection.find({ $and: [{
"users": ObjectId("56b0e547a838b5a45b4d0100")
}, {
"users": ObjectId("56a7e16e37e5adf32b97cc3d")
}]})
Response gives me two records.
This request gives me the correct response:
db.collection.find({"users" : [
ObjectId("56b0e547a838b5a45b4d0100"), // 0
ObjectId("56a7e16e37e5adf32b97cc3d") // 1
]})
but if record has an array like this:
{
"_id" : ObjectId("56b7e6966213e8d142ef55b7"),
"users" : [
ObjectId("56a7e16e37e5adf32b97cc3d"), // 1
ObjectId("56b0e547a838b5a45b4d0100") // 0
]
}
it doesn't work
$all, $eq, $in also doesn't work
db.rooms.find({
users: {
$all: [
ObjectId("56a7e16e37e5adf32b97cc3d"),
ObjectId("56b0e547a838b5a45b4d0100")
]
}
})
I need to find rows where [1,2] == [1,2] or [1,2] == [2,1]
not where [1,2,3] == [1,2]
I will appreciate if somebody can help me.
If all you expect is the resulting document with "only" those two array entries, then the combination of conditions you want is $all and $size:
db.rooms.find({
"users": {
"$all": [
ObjectId("56b0e547a838b5a45b4d0100"),
ObjectId("56a7e16e37e5adf32b97cc3d")
],
"$size": 2
}
})
Where $all is basically an $and with shorter syntax, and the $size retricts that since the list as n entries, then you only want to match something of that particular length/size.
This is better than specifying the array directly, since it will match in either order, as opposed to this statement that would not match considering the order is different and therefore not an "exact" match:
db.rooms.find({
"users": [
ObjectId("56a7e16e37e5adf32b97cc3d"),
ObjectId("56b0e547a838b5a45b4d0100")
]
})
So logically the array contains "all" the specified entries, and is the same "size" as the input and no different.

Sort search results by array index in Elasticsearch

I have records like that:
// tags vary in order within array
{
name : 'Karl',
tags : [
'java',
'html',
'javascript'
]
},
{
name : 'John',
tags : [
'html',
'java',
'javascript'
]
}
I run a bool query on tags:
"query" : {
"bool" : {
"must" : [
{
"term" : "java"
}
]
}
}
I want Karl to be the first search result, because 'java' has a lower index in his tags array. Unfortunately my query doesn't care about the index, overall results are ok, but order of results seems to be random.
How can I force Elasticsearch to consider the array index?
thx!
If you need this information, then you're going to have to store the index of each element within that element:
{
name : 'Karl',
tags : [
'java',
'html',
'javascript'
],
index : 0
},
{
name : 'John',
tags : [
'html',
'java',
'javascript'
],
index : 1
}
Then you can sort on this index subfield:
"query" : {
"bool" : {
"must" : [
{
"term" : "java"
}
]
},
"sort" : [
"arrayFieldName.index" : "asc"
]
}

Resources