How to unwind/merge arrays from hierarchical document structure? - merge

I have a nested document structure and I am able to filter it with pluck to show the relevant parts:
Is there an elegant way to merge all entries of the last level to a single array?
Expected result (entries are not unique on purpose):
[
'3425b91f-f019-4db3-ad56-c336bf55279b',
'3d07946e-183d-4992-9acd-676f5122e1b1',
'3425b91f-f019-4db3-ad56-c336bf55279b',
'3d07946e-183d-4992-9acd-676f5122e1b1',
'2cd652a6-4dcd-4920-9592-d4cdc5a034bf',
'70fe1812-e1de-447b-ac4f-d89fead4756d',
'2cd652a6-4dcd-4920-9592-d4cdc5a034bf',
'70fe1812-e1de-447b-ac4f-d89fead4756d'
]
I tried to use
r.table('periods')['regions']['sites']['plants']['product']['process']['technologies'].run()
but it gives the error "Cannot perform bracket on a sequence of sequences".
=> Is there some alternative operator to get a merged sequence instead a "sequence of sequences" for each step?
Something like
r.table('periods').unwind('regions.sites.plants.product.process.technologies')
Here is some python code to create example data:
from rethinkdb import RethinkDB
r = RethinkDB()
r.connect({}).repl()
r.table_create("periods")
def uniqueid():
return r.uuid().run()
periodid_first = uniqueid()
periodid_second = uniqueid()
companyid_2000 = uniqueid()
companyid_2001 = uniqueid()
technologyid_2000_first = uniqueid()
technologyid_2000_second = uniqueid()
technologyid_2001_first = uniqueid()
technologyid_2001_second = uniqueid()
energy_carrierid_2000_first = uniqueid()
energy_carrierid_2000_second = uniqueid()
energy_carrierid_2001_first = uniqueid()
energy_carrierid_2001_second = uniqueid()
periods = [
{
'id': periodid_first,
'start': 2000,
'end': 2000,
# 'sub_periods': [],
'regions': [
{
'id': 'DE',
# 'sub_regions': [],
'sites': [
{
'id': 'first_site_in_germany',
'company': companyid_2000, # => verweist auf periods => companies
'plants': [
{
'id': 'qux',
'product': {
'id': 'Ammoniak',
'process': {
'id': 'SMR+HB',
'technologies': [
technologyid_2000_first, # => verweist auf periods => technologies
technologyid_2000_second
]
}
}
}
]
}
]
},
{
'id': 'FR',
# 'sub_regions': [],
'sites': [
{
'id': 'first_site_in_france',
'company': companyid_2000, # => verweist auf periods => companies
'plants': [
{
'id': 'qux',
'product': {
'id': 'Ammoniak',
'process': {
'id': 'SMR+HB',
'technologies': [
technologyid_2000_first, # => verweist auf periods => technologies
technologyid_2000_second
]
}
}
}
]
}
]
}
],
'companies': [
{
'id': companyid_2000,
'name': 'international_company'
}
],
'technologies': [
{
'id': technologyid_2000_first,
'name': 'SMR',
'specific_cost_per_year': 123,
'specific_energy_consumptions': [
{
'energy_carrier': energy_carrierid_2000_first,
'specific_consumption': 5555
}, # => verweist auf periods => energy_carriers
{
'energy_carrier': energy_carrierid_2000_second,
'energy_consumption': 2333
}
]
},
{
'id': technologyid_2000_second,
'name': 'HB',
'specific_cost_per_year': 1234,
'specific_energy_consumptions': [
{
'energy_carrier': energy_carrierid_2000_first,
'specific_consumption': 555
}, # => verweist auf periods => energy_carriers
{
'energy_carrier': energy_carrierid_2000_second,
'energy_consumption': 233
}
]
}
],
'energy_carriers': [
{
'id': energy_carrierid_2000_first,
'name': 'oil',
'group': 'fuel'
},
{
'id': energy_carrierid_2000_second,
'name': 'gas',
'group': 'fuel'
},
{
'id': uniqueid(),
'name': 'conventional',
'group': 'electricity'
},
{
'id': uniqueid(),
'name': 'green',
'group': 'electricity'
}
],
'networks': [
{
'id': uniqueid(),
'name': 'gas',
'sub_networks': [],
'pipelines': [
]
},
{
'id': uniqueid(),
'name': 'gas',
'sub_networks': [],
'pipelines': [
]
}
]
},
{
'id': periodid_second,
'start': 2001,
'end': 2001,
# 'sub_periods': [],
'regions': [
{
'id': 'DE',
# 'sub_regions': [],
'sites': [
{
'id': 'first_site_in_germany',
'company': companyid_2001, # => verweist auf periods => companies
'plants': [
{
'id': 'qux',
'product': {
'id': 'Ammoniak',
'process': {
'id': 'SMR+HB',
'technologies': [
technologyid_2001_first, # => verweist auf periods => technologies
technologyid_2001_second
]
}
}
}
]
}
]
},
{
'id': 'FR',
# 'sub_regions': [],
'sites': [
{
'id': 'first_site_in_france',
'company': companyid_2001, # => verweist auf periods => companies
'plants': [
{
'id': 'qux',
'product': {
'id': 'Ammoniak',
'process': {
'id': 'SMR+HB',
'technologies': [
technologyid_2001_first, # => verweist auf periods => technologies
technologyid_2001_second
]
}
}
}
]
}
]
}
],
'companies': [
{
'id': companyid_2001,
'name': 'international_company'
}
],
'technologies': [
{
'id': technologyid_2001_first,
'name': 'SMR',
'specific_cost_per_year': 123,
'specific_energy_consumptions': [
{
'energy_carrier': energy_carrierid_2001_first,
'specific_consumption': 5555
}, # => verweist auf periods => energy_carriers
{
'energy_carrier': energy_carrierid_2001_second,
'energy_consumption': 2333
}
]
},
{
'id': technologyid_2001_second,
'name': 'HB',
'specific_cost_per_year': 1234,
'specific_energy_consumptions': [
{
'energy_carrier': energy_carrierid_2001_first,
'specific_consumption': 555
}, # => verweist auf periods => energy_carriers
{
'energy_carrier': energy_carrierid_2001_second,
'energy_consumption': 233
}
]
}
],
'energy_carrieriers': [
{
'id': energy_carrierid_2001_first,
'name': 'oil',
'group': 'fuel'
},
{
'id': energy_carrierid_2001_second,
'name': 'gas',
'group': 'fuel'
},
{
'id': uniqueid(),
'name': 'conventional',
'group': 'electricity'
},
{
'id': uniqueid(),
'name': 'green',
'group': 'electricity'
}
],
'networks': [
{
'id': uniqueid(),
'name': 'gas',
'sub_networks': [],
'pipelines': [
]
},
{
'id': uniqueid(),
'name': 'gas',
'sub_networks': [],
'pipelines': [
]
}
]
}
]
r.table('periods') \
.insert(periods) \
.run()
Related:
RethinkDB: RqlRuntimeError: Cannot perform bracket on a sequence of sequences

Nested concat_map in combination with r.row operator and bracket drill down does the trick:
r.table('periods') \
.concat_map(r.row['regions']) \
.concat_map(r.row['sites']) \
.concat_map(r.row['plants'])['product']['process'] \
.concat_map(r.row['technologies']) \
.run()

Related

ipycytoscape, draw subgraph

I'm noob in ipycytoscape and Jupyter and seems need help. I'm trying to find a sutable way to show/draw subgraph after I click by node.
For example.
I have graph with node1---node2---node3 . I click by node1 and want to show
node1 --- node2.1 - node2.2 node2.3 --- node3.
Don't know how to make this. Tried to find in Google but coudn't find any suitable approach.
This is my simplest code for this. I no idea how to show and aftger hide (expand and collapse) subgraph. This code don't have this part.
I heard something about layouts but couldn't find sutable example for ipycytoscape.
Any ideas are welcome.
import ipycytoscape
import ipywidgets as widgets
import networkx as nx
counter = 0 # need to make new nodes with uniq id
data = {
'nodes': [
{ 'data': { 'id': 'desktop', 'name': 'Cytoscape', 'href': 'http://cytoscape.org' } },
{ 'data': { 'id': 'a', 'name': 'Grid', 'href': 'http://cytoscape.org', 'parent': 'Cola' } },
{ 'data': { 'id': 'c', 'name': 'Popper', 'href': 'http://cytoscape.org', 'parent': 'Cola' } },
{ 'data': { 'id': 'b', 'name': 'Cola', 'href': 'http://cytoscape.org' } },
{ 'data': { 'id': 'js', 'name': 'Cytoscape.js', 'href': 'http://js.cytoscape.org' } }
],
'edges': [
{'data': { 'source': 'desktop', 'target': 'js' }},
{'data': { 'source': 'a', 'target': 'b' }},
{'data': { 'source': 'a', 'target': 'c' }},
{'data': { 'source': 'b', 'target': 'c' }},
{'data': { 'source': 'js', 'target': 'b' }}
]
}
custom_inherited = ipycytoscape.CytoscapeWidget()
custom_inherited.graph.add_graph_from_json(data)
custom_inherited.set_style([{
'selector': 'node',
'css': {
'content': 'data(name)',
'text-valign': 'center',
'color': 'white',
'text-outline-width': 2,
'text-outline-color': 'green',
'background-color': 'green'
}
},
{
'selector': 'node[classes = "collapsed-childS"]',
'css': {
'background-color': 'red',
'line-color': 'blue',
'target-arrow-color': 'red',
'source-arrow-color': 'red',
'text-outline-color': 'red'
},
}
])
# When I click to node by mouse I add some nodes. I made this because don't know how to show and hide subgraph. The question in this place.
def paint_blue(event):
global counter
for node in cytoscapeobj.graph.nodes:
if node.data['id'] == event['data']['id']:
auxNode = node
auxNode.data['classes'] = "collapsed-childS"
station_NUR = ipycytoscape.Node()
station_NUR.data['id'] = "NUR" + str(counter)
station_NUR.data['name'] = station_NUR.data['id']
station_NUR.data['classes'] = "collapsed-childS"
station_FRA = ipycytoscape.Node()
station_FRA.data['id'] = "FRA" + str(counter)
station_FRA.data['name'] = station_FRA.data['id']
station_FRA.data['classes'] = "collapsed-childS"
new_edge1 = ipycytoscape.Edge()
new_edge1.data['id'] = "line6" + str(counter)
new_edge1.data['source'] = station_NUR.data['id']
new_edge1.data['target'] = station_FRA.data['id']
new_edge2 = ipycytoscape.Edge()
new_edge2.data['id'] = "line7" + str(counter)
new_edge2.data['source'] = station_NUR.data['id']
new_edge2.data['target'] = auxNode.data['id']
custom_inherited.graph.add_node(station_NUR)
custom_inherited.graph.add_node(station_FRA)
custom_inherited.graph.add_edges([new_edge1,new_edge2])
counter = counter + 1
custom_inherited.on('node', 'click', paint_blue)
custom_inherited

Flutter: how to return the value by using other value inside the List<Map>

I have a List<Map<String, String>> like below
[
{ 'name': 'John', 'id': 'aa' },
{ 'name': 'Jane', 'id': 'bb' },
{ 'name': 'Lisa', 'id': 'cc' },
]
And, the ID list **List** as ['bb', 'aa']. By using the ID list, I want to return a new list ['Jane', 'John'] as **List _selectedList**.
I have tried to do it with the .**indexWhere**, however, I am stuck on the List where it has more than one value.
How can I return the List only with the name-value when there is more than one value to look for?
void main() {
var a = [
{ 'name': 'John', 'id': 'aa' },
{ 'name': 'Jane', 'id': 'bb' },
{ 'name': 'Lisa', 'id': 'cc' },
];
var b = ['bb', 'aa'];
var c = a.where((m) => b.contains(m['id'])).map((m) => m['name']);
print(c);
}
Result
(John, Jane)
Use a set to filter out the IDs efficiently.
var ids = ["aa", "cc"];
var idSet = Set<String>.from(ids);
var json = [
{ 'name': 'John', 'id': 'aa' },
{ 'name': 'Jane', 'id': 'bb' },
{ 'name': 'Lisa', 'id': 'cc' },
];
var _selectedList = json.where((data) => idSet.contains(data["id"]))
.map((data) => data["name"]).toList();
print(_selectedList);
Here, .where filters out the data where the ID matches one in the input list "IDs". Sets make the process efficient. Then, the resultant objects are passed to .map where the "name" field is extracted. Finally, the whole thing is converted into a list thus returning the list of names.
Output of the above code:
[John, Lisa]

How to use where method with null boolean

I have a list like this:
[
{'country': ' Wakanda', 'languages': null},
{
'country': 'USA',
'languages': [
{'language': 'English'}
]
},
{
'country': 'Germany',
'languages': [
{'language': 'German'}
]
},
{
'country': ' Ireland',
'languages': [
{'language': 'English'},
{'language': 'Irish'}
]
}
]
I try to create a new list that 'language' contains 'eng'toLowwerCase(), but the error is Failed assertion: boolean expression must not be null
So pls help me, this is the full code:
void main() async {
List list = [
{'country': ' Wakanda', 'languages': null},
{
'country': 'USA',
'languages': [
{'language': 'English'}
]
},
{
'country': 'Germany',
'languages': [
{'language': 'German'}
]
},
{
'country': ' Ireland',
'languages': [
{'language': 'English'},
{'language': 'Irish'}
]
}
];
List filterList = List.from(list).where((e) {
return e['languages']?.any((l) => l['language'].toLowwerCase().contains('eng').toLowwerCase());
}).toList();
print(filterList);
}
The callback to Iterable.where must return a non-nullable bool type. Your callback potentially returns null if e['languages'] returns null:
return e['languages']?.any(
(l) => l['language'].toLowwerCase().contains('eng').toLowwerCase()
);
The way to fix it is to handle null. You can use x ?? y to provide a default value of y if x is null:
return e['languages']?.any(
(l) => l['language'].toLowwerCase().contains('eng').toLowwerCase()
) ?? false;
I'll also point out that:
toLowerCase() is misspelled.
List.from(list).where(...).toList() is redundant and could be just list.where(...).toList().
Try something like this
List filterList = List.from(list).where((e) {
// Avoid check null valĂșes
if (e['languages'] == null) {
return false;
}
return e['languages']?.any(
(l) => l['language'].toLowwerCase().contains('eng').toLowwerCase());
}).toList();
Also you can validate language child value
void main() async {
List list = [
{'country': ' Wakanda', 'languages': null},
{
'country': 'USA',
'languages': [
{'language': 'English'}
]
},
{
'country': 'Germany',
'languages': [
{'language': 'German'}
]
},
{
'country': ' Ireland',
'languages': [
{'language': 'English'},
{'language': 'Irish'}
]
}
];
List filterList = List.from(list).where((e) {
try{
return e['languages']?.any((l) =>
l['language'].toLowwerCase().contains('eng').toLowwerCase());
}).toList();
}
catch(e){
return [''];
}
print(filterList);
}

PyMongo: Removing a nested object without knowing the key

Let's say I have a collection that looks like this:
{
'_id': ObjectId('abc'),
'customer': 'bob',
'products': {
'1234':
{'name': 'Shirt',
'productID': 5
},
'5679': {
'name': 'Hat',
'productID': 5
}
}
'1011': {
'name': 'Jeans',
'productID': 9
}
}
}
I am looking to remove all nested objects whose 'productID' property is 5, so the collection would look like this afterwards:
{'_id': ObjectId('abc'),
'name': 'bob',
'products': {
'1011': {
'name': 'Jeans',
'productID': 9
}
}
}
I know the following information:
customer: bob
productID: 5
Is it possible to do a wildcard on 'products'? Something like this (it does not work):
db.update({'customer':'bob'}, {'$unset': {'products.*': {'productID': 9}})
If you have a choice, refactor your data to make each item a list element, e.g.
{
'customer': 'bob',
'products': [
{'code': '1234',
'name': 'Shirt',
'productID': 5
},
{'code': '5679',
'name': 'Hat',
'productID': 5
},
{'code': '1011',
'name': 'Jeans',
'productID': 9
}
]
}
Then your update becomes a piece of cake:
db.mycollection.update_one({'customer': 'bob'}, {'$pull': {'products': {'productID': 5}}})
result:
{
"customer": "bob",
"products": [
{
"code": "1011",
"name": "Jeans",
"productID": 9
}
]
}
Persisting with poor choices of schema will no yield long term rewards.

Scala - reformatting hash-map

I have some Python code that processes a fairly complex hashmap (Example Input), restructures it and creates (Example Output) a simplified version of it. I'm looking for the best way to tackle this with Scala, i.e. built in or external libs? I'm new to Scala and just getting to grips with it, so some guidance here would be really helpful.
This was fairly easy to do using Python and I'm hoping that will be the with Scala.
Input:
data_in = {
'map': {
'stats': {
'uphosts': u'3',
'timestr': u'Thu Mar 20 18:18:09 2014',
'downhosts': u'0',
'totalhosts': u'3',
'elapsed': u'1.71'
},
'scaninfo': {
u'tcp': {
'services': u'80,443',
'method': u'syn'
}
},
'command_line': u'command goes here'
},
'scan': {
u'2a00:2384:0:208f::15': {
'status': {
'state': u'up',
'reason': u'nd-response'
},
'hostname': u'static.xyz.com',
'vendor': {
u'00:0C:67:99:6f:96': u'VMware'
},
'addresses': {
u'mac': u'00:gf:29:99:6D:96',
u'ipv6': u'a848:2384:0:3456::15'
},
u'tcp': {
80: {
'product': '',
'state': u'open',
'version': '',
'name': u'http',
'conf': u'3',
'extrainfo': '',
'reason': u'syn-ack',
'cpe': ''
},
443: {
'product': '',
'state': u'open',
'version': '',
'name': u'https',
'conf': u'3',
'script': {
u'ssl-cert': u'place holder'
},
'extrainfo': '',
'reason': u'syn-ack',
'cpe': ''
}
}
},
u'2a00:2384:0:208f::16': {
'status': {
'state': u'up',
'reason': u'nd-response'
},
'hostname': u'static.edf.com',
'vendor': {
u'00:0C:55:AE:33:ff': u'VMware'
},
'addresses': {
u'mac': u'00:54:29:fg:55:0F',
u'ipv6': u'8938:8584:0:8685::16'
},
u'tcp': {
80: {
'product': '',
'state': u'open',
'version': '',
'name': u'http',
'conf': u'3',
'extrainfo': '',
'reason': u'syn-ack',
'cpe': ''
},
443: {
'product': '',
'state': u'open',
'version': '',
'name': u'https',
'conf': u'3',
'script': {
u'ssl-cert': u'place holder'
},
'extrainfo': '',
'reason': u'syn-ack',
'cpe': ''
}
}
}
}
}
Required output:
data_out_1 = [
{'address': u'2a00:2384:0:208f::15',
'hostname': u'static.xyz.com',
'ports': {80: {'reason': u'syn-ack', 'state': u'open'},
443: {'reason': u'syn-ack',
'ssl_cert': u'place holder',
'state': u'open'}}},
{'address': u'2a00:2384:0:208f::16',
'hostname': u'static.edf.com',
'ports': {80: {'reason': u'syn-ack', 'state': u'open'},
443: {'reason': u'syn-ack',
'ssl_cert': u'place holder',
'state': u'open'}}}]
That isn't typesafe.
Hashmaps can't store different types of data*. Start by creating datastructures to hold the input data (case classes will help here).
So your stats object might look like
case class Stats(uphosts: Int, timeStr: Datetime, downhosts: Int, totalHosts: Int, elapsed:Double)
ignoring subtyping here for the moment.