Ordering array in twig after sorting it - twig

Let's say I'm having array in twig
{% set temp = [
{"name": 'Tom', 'lname': 'Marko'},
{"name": 'Nick', 'lname': 'Montana'},
{"name": 'Tina', 'lname': 'Marko'},
{"name": 'Mike', 'lname': 'Miles'}
] %}
Is it possible to first sort it by lname and then order by name right in template and make it look like
{% set temp = [
{"name": 'Tina', 'lname': 'Marko'},
{"name": 'Tom', 'lname': 'Marko'},
{"name": 'Mike', 'lname': 'Miles'},
{"name": 'Nick', 'lname': 'Montana'}
] %}
or I have to sort and order it before passing to template or create extension to make it possible in template?

According to https://twig.symfony.com/doc/2.x/filters/sort.html
You would need:
{% set temp = [
{"name": 'Tom', 'lname': 'Marko'},
{"name": 'Nick', 'lname': 'Montana'},
{"name": 'Tina', 'lname': 'Marko'},
{"name": 'Mike', 'lname': 'Miles'}
]%}
{% for tmp in temp|sort((a, b) => (a.name <=> b.name))|sort((a, b) => (a.lname <=> b.lname)) %}
{{ tmp.name }} {{ tmp.lname }}
{% endfor %}
This yeilds:
Tina Marko
Tom Marko
Mike Miles
Nick Montana
demo

Related

How can I group an array of objects by key using node typescript?

const cars = [
{
'make': 'audi',
'model': 'r8',
'year': '2012'
},{
'make': 'kia',
'model': 'optima',
'year': '2013'
},
];
const details = [
{
'make': 'audi',
'owner': 'user1',
'features': 'abc'
},{
'make': 'audi',
'owner': 'user2',
'features': 'xyz'
},
{
'make': 'kia',
'owner': 'user3',
'features': 'xyz'
},
{
'make': 'kia',
'owner': 'user4',
'features': 'xyz'
},
];
const result = [
{
'make': 'audi',
'model': 'r8',
'year': '2012',
"Details": [
{
'make': 'audi',
'owner': 'user1',
'features': 'abc'
},{
'make': 'audi',
'owner': 'user2',
'features': 'xyz'
}
]
},
{
'make': 'kia',
'model': 'optima',
'year': '2013',
"Details": [
{
'make': 'kia',
'owner': 'user3',
'features': 'xyz'
},
{
'make': 'kia',
'owner': 'user4',
'features': 'xyz'
},
]
},
];
The idea is to first group details array into a collection of make -> [detail]. Time complexity is O(n), and space complexity is also O(n) since we creating a new collection.
After that we can merge the new collection into cars array under the assumption that each make appears only once in the cars array (if not we will need a middleware step). Here time complexity is also O(n)
// group details collection
const groupDetails = details.reduce((m, detail) => {
const items = m.get(detail.make) || [];
m.set(detail.make, [ ...items, ...[detail] ]);
return m;
}, new Map<string, unknown[]>());
// merge new collection into cars array
const carsDetails = cars.map(car => {
const details = groupDetails.get(car.make) || [];
return { ...car, ...{ Details: details }};
});
See running code example in Typescript playground

MongoDB $unwind and keep array field with each unwound document for reference

I would like to keep the original array field with each unwound document.
Example: When unwinding the members array of a band, I would like to keep the original members array with each doc so I can reference the other members
{ 'name': 'the crazies', 'member': 'Tom', 'othermembers': [ 'Tom', 'Mike', 'Sally' ] }
{ 'name': 'the crazies', 'member': 'Mike', 'othermembers': [ 'Tom', 'Mike', 'Sally' ] }
{ 'name': 'the crazies', 'member': 'Sally', 'othermembers': [ 'Tom', 'Mike', 'Sally' ] }
Ultimately the members array should not include the name of the member already in the 'name' field but I will take what I can get if anyone has any ideas.
An approach that works was to do a $lookup on itself by the band id but seems kind of clumsy.
band.aggregate()
.match( 'whatever criteria' )
.lookup({ from: 'bands', localField: '_id', foreignField: '_id', as 'othermembers')
.unwind({ path: 'members')
.project({
'name': 1
'member': '$members.name',
'othermembers.members.name': 1;
})
Thoughts???
Before unwinding the members array, project members array as two new fields and then unwind any one of the two new fields. For example
{
"_id" : ObjectId("5c5ca7184ef14365b786e11f"),
"a" : [
10,
20,
30
],
"b" : "hello"
}
For the above data, I am using the below query
db.testColl.aggregate([
{$project: {old_arr: "$a", new_arr: "$a"}},
{$unwind: {path: "$old_arr"}}
])
The result I get is
{
"_id" : ObjectId("5c5ca7184ef14365b786e11f"),
"old_arr" : 10,
"new_arr" : [
10,
20,
30
]
}
{
"_id" : ObjectId("5c5ca7184ef14365b786e11f"),
"old_arr" : 20,
"new_arr" : [
10,
20,
30
]
}
{
"_id" : ObjectId("5c5ca7184ef14365b786e11f"),
"old_arr" : 30,
"new_arr" : [
10,
20,
30
]
}
So the old_arr field is unwinded, but for each document, you will have new_arr field with all values.

How can I query mongo to find arrays that contain TWO elements from another array

Let's say I have the following documents in mongo:
{_id: 0, tags: ['first', 'second', 'third', fourth']},
{_id: 1, tags: ['fifth', 'seventh', 'first', second']},
{_id: 2, tags: ['eigth', 'awesometh', 'fancyth']},
{_id: 3, tags: ['fourth', 'fifteenth', 'something']},
I want to find documents which contain TWO OR MORE from the following array: ['first', 'second', third', 'fourth', 'fifteenth']
The only idea I have so far is to generate I giant query with a clause for each combination, like so:
{$or: [
{tags: {$in: ['first', 'second']}},
{tags: {$in: ['second', 'third']}},
{tags: {$in: ['first', 'third']}},
...etc...
]
}
This is obviously not an elegant solution. Is there a better way?
You can do this with an aggregate pipeline that uses $setIntersection to find the matched tags, and then $size to count them:
var tags = ['first', 'second', 'third', 'fourth', 'fifteenth'];
db.test.aggregate([
// Project the original doc along with a count of the tag matches
{$project: {
_id: 0,
matches: {$size: {$setIntersection: ['$tags', tags]}},
doc: '$$ROOT'
}},
// Filter to just those docs with at least 2 matches
{$match: {matches: {$gte: 2}}}
])
Output
{ "matches": 4, "doc": { "_id": 0, "tags": ["first", "second", "third", "fourth"] }}
{ "matches": 2, "doc": { "_id": 1, "tags": ["fifth", "seventh", "first", "second"] }}
{ "matches": 2, "doc": { "_id": 3, "tags": ["fourth", "fifteenth", "something"] }}

Merge and Aggregate data in Groovy

I was wondering what the best way to aggregate this data would be in Groovy?
Lets say I have the following data:
[
[id: 1, name: bob, age:20, numberOfPackages: 10, numberOfPurchases:20 ],
[id: 1, name: bob, age:20, numberOfPackages: 5, numberOfPurchases:6 ],
[id: 2, name: Rob, age:22, numberOfPackages: 3, numberOfPurchases:5 ],
]
and I want to transform it to the following (merge id/name/age but sum price/number of purchases per id):
[
[id: 1, name: bob, age:20, numberOfPackages: 15, numberOfPurchases:26 ],
[id: 2, name: Rob, age:22, numberOfPackages: 3, numberOfPurchases:5 ],
]
Summing the prices, and the number of purchases separately makes little sense, do you mean:
def data = [
[id: 1, name: 'bob', age:20, price: 10, numberOfPurchases:20],
[id: 1, name: 'bob', age:20, price: 5, numberOfPurchases:6],
[id: 2, name: 'rob', age:22, price: 3, numberOfPurchases:5]
]
data.groupBy { [id:it.id, name:it.name, age:it.age] }.collect { k, v ->
[id:k.id,
name:k.name,
age:k.age,
spend:v.collect { it.price * it.numberOfPurchases }.sum()]
}
Which gives:
[
[id:1, name:'bob', age:20, spend:230],
[id:2, name:'rob', age:22, spend:15]
]
It may be e.g.:
def data = [
[id: 1, name: 'bob', age:20, price: 10, numberOfPurchases:20 ],
[id: 1, name: 'bob', age:20, price: 5, numberOfPurchases:6 ],
[id: 2, name: 'rob', age:22, price: 3, numberOfPurchases:5 ],
]
data.groupBy { it.id }.collectEntries {
[
(it.key): [
name: it.value.name.first(),
age: it.value.first(),
price: it.value.sum { it.price },
numberOfPurchases: it.value.sum { it.numberOfPurchases },
]
]
}

Docusign Compoite Templates multiple server templates

I'm trying to render two templates together using the compositeTemplates attribute. However only the second one gets included. I believe this structure is correct because I can get one or the other if I just comment one out. According to the documentation all I should need to set is the sequence. How can I get both server templates to be included in one envelope?
'emailSubject': "test doc",
'emailBurb': 'this is a test doc',
'status': 'sent',
'compositeTemplates': [{
'serverTemplates': [
# LT
{
'sequence': '1',
'templateId': '9FA06158-4789-4473-B435-F81BF2C7D1D0',
},
],
'serverTemplates': [
# ST
{
'sequence': '2',
'templateId': '235E5E2C-D4F1-4043-AE7E-793DD89268F3',
},
],
'inlineTemplates': [{
'sequence': '1',
'recipients': {
'signers': [{
'email': send_to,
'name': "Tester",
'recipientId': '1',
'roleName': 'Signer',
'tabs': {
'textTabs': [
{
'tabLabel': 'full_address',
'value': 'Massachusetts'
},
],
},
}],
},
}],
'inlineTemplates': [{
'sequence': '2',
'recipients': {
'signers': [{
'email': send_to,
'name': "Tester",
'recipientId': '1',
'roleName': 'Signer',
'tabs': {
'textTabs': [
{
'tabLabel': 'full_address',
'value': 'Massachusetts'
},
],
},
}],
},
}],
}]
The request you have there is actually combining the two server-templates. The sequence in this case determines which documents/recipients take priority. To included them both as a separate documents, you'd want something more like the below. This has two composite templates. Each one combines a server-side template with an in-line template. I haven't tested this, but it should get you going.
'emailSubject': "test doc",
'emailBurb': 'this is a test doc',
'status': 'sent',
'compositeTemplates': [{
'serverTemplates': [
# LT
{
'sequence': '1',
'templateId': '9FA06158-4789-4473-B435-F81BF2C7D1D0',
},
],
'inlineTemplates': [{
'sequence': '2',
'recipients': {
'signers': [{
'email': send_to,
'name': "Tester",
'recipientId': '1',
'roleName': 'Signer',
'tabs': {
'textTabs': [
{
'tabLabel': 'full_address',
'value': 'Massachusetts'
},
],
},
}],
},
}]
},
{
'serverTemplates': [
# ST
{
'sequence': '1',
'templateId': '235E5E2C-D4F1-4043-AE7E-793DD89268F3',
},
],
'inlineTemplates': [{
'sequence': '2',
'recipients': {
'signers': [{
'email': send_to,
'name': "Tester",
'recipientId': '1',
'roleName': 'Signer',
'tabs': {
'textTabs': [
{
'tabLabel': 'full_address',
'value': 'Massachusetts'
},
],
},
}],
},
}],
}]

Resources