I have performed union in my query which gives me the following output
{
key1 = value1,
key2 = value2
},
{
key3 = value3
}
I need output as follows,
{
key1 = value1,
key2 = value2,
key3 = value3
}
You have to deconstruct and reconstruct the maps. This operation is described in some detail in Gremlin Recipes if you want to read more.
The following code gets you to the position of your union():
gremlin> x = [[key1:"value1",key2:"value2"],[key3:"value3"]]
==>[key1:value1,key2:value2]
==>[key3:value3]
gremlin> g.inject(x).unfold()
==>[key1:value1,key2:value2]
==>[key3:value3]
Then you just unfold() those maps to map entries (i.e. key/value pairs) and group() them back together:
gremlin> g.inject(x).unfold().unfold().group().by(keys).by(values)
==>[key1:[value1],key2:[value2],key3:[value3]]
gremlin> g.inject(x).unfold().unfold().group().by(keys).by(select(values))
==>[key1:value1,key2:value2,key3:value3]
Related
I have tables like below
import sqlalchemy as sa
class A(Base):
id = sa.Column(sa.Integer)
name = sa.Column(sa.String)
class B(Base):
id = sa.Column(sa.Integer)
a_id = sa.Column(sa.Integer)
and has query:
# Basic query
query = sa.select(B).join(A, A.id == B.a_id)
result = await session.execute(query)
results = result.scalars().all()
How should I change to get desired result?
query = sa.select(B).join(A, A.id == B.a_id)
result = session.execute(query)
results = result.scalars().all()
# Problem
# SOME_KEY should be indicated in query as loading column
# SOME_KEY's type should be A class
# I want below thing
results[0].SOME_KEY.name # it should give joined `A` entity's property value
I have read documentation, have seen loading techniques, but could not find solution , it is mostly for relations.
Arbitrary query with multiple objects per result
with Session(engine) as session:
for (b, a) in session.execute(select(B, A).join(A, B.a_id == B.id)).all():
print (b, a)
Relationship without ForeignKey
from sqlalchemy.orm import Session, declarative_base, aliased, relationship, remote, foreign
class A(Base):
__tablename__ = 'a_table'
id = Column(Integer, primary_key=True)
name = Column(String)
b_list = relationship('B', primaryjoin="remote(A.id) == foreign(B.a_id)", back_populates='a')
class B(Base):
__tablename__ = 'b_table'
id = Column(Integer, primary_key=True)
a_id = Column(Integer)
a = relationship('A', primaryjoin="remote(A.id) == foreign(B.a_id)", back_populates='b_list')
with Session(engine) as session:
for (b,) in session.execute(select(B).join(B.a)).all():
print (b, b.a_id, b.a, b.a.id, b in b.a.b_list)
How to output Gremlin query from a Java GraphTraversal object? The default output (graphTraversal.toString()) looks like [HasStep([~label.eq(brand), name.eq(Nike), status.within([VALID])])] which is not easy to read.
Gremlin provides the GroovyTranslator class to help with that. Here is an example.
// Simple traversal we can use for testing a few things
Traversal t =
g.V().has("airport","region","US-TX").
local(values("code","city").
fold());
// Generate the text form of the query from a Traversal
String query;
query = GroovyTranslator.of("g").
translate(t.asAdmin().getBytecode());
System.out.println("\nResults from GroovyTranslator on a traversal");
System.out.println(query);
This is taken from a set of examples located here: https://github.com/krlawrence/graph/blob/master/sample-code/RemoteWriteText.java
You can use getByteCode() method on a DefaultGraphTraversal to get output gremlin query.
For example, consider the following graph
Graph graph = TinkerGraph.open();
Vertex a = graph.addVertex(label, "person", "name", "Alex", "Age", "23");
Vertex b = graph.addVertex(label, "person", "name", "Jennifer", "Age", "20");
Vertex c = graph.addVertex(label, "person", "name", "Sophia", "Age", "22");
a.addEdge("friends_with", b);
a.addEdge("friends_with", c);
Get a graph Traversal as following:
GraphTraversalSource gts = graph.traversal();
GraphTraversal graphTraversal =
gts.V().has("name","Alex").outE("friends_with").inV().has("age", P.lt(20));
Now you can get your traversal as a String as:
String traversalAsString = graphTraversal.asAdmin().getBytecode().toString();
It gives you output as:
[[], [V(), has(name, Alex), outE(friends_with), inV(), has(age, lt(20))]]
It is much more readable, almost like the one you have provided as the query. You can now modify/parse the string to get the actual query if you want like replacing [,], adding joining them with . like in actual query.
I am trying to get the top 5 records ordered on a specific value in Cosmos DB but I am getting stuck at getting the records ordered.
The query is done on the following document:
{
"id": string,
"Compliant": bool,
"DefinitionId": int,
"DefinitionPeriod": string,
"EventDate": date,
"HerdProfileId": int,
"Period": int,
"Value": int
}
What i have tried:
1st try
SELECT TOP 5 cr.HerdProfileId, cr.Compliant, cr.NonCompliant, cr.NullCompliant FROM (
SELECT
c.HerdProfileId,
SUM(comp) as Compliant,
SUM(noncomp) as NonCompliant,
SUM(nullcomp) as NullCompliant
FROM c
JOIN(SELECT VALUE COUNT(c.id) FROM c WHERE c.Compliant = true) comp
JOIN(SELECT VALUE COUNT(c.id) FROM c WHERE c.Compliant = false) noncomp
JOIN(SELECT VALUE COUNT(c.id) FROM c WHERE c.Compliant = null) nullcomp
WHERE c.Period = 201948
GROUP BY c.HerdProfileId) cr
WHERE cr.NonCompliant > 0
ORDER BY cr.NonCompliant
results in: Unsupported ORDER BY clause. ORDER BY item expression could not be mapped to a document path
2nd try:
SELECT TOP 5 cr.HerdProfileId, cr.Compliant, cr.NonCompliant, cr.NullCompliant FROM (
SELECT
c.HerdProfileId,
SUM(comp) as Compliant,
SUM(noncomp) as NonCompliant,
SUM(nullcomp) as NullCompliant
FROM c
JOIN(SELECT VALUE COUNT(c.id) FROM c WHERE c.Compliant = true) comp
JOIN(SELECT VALUE COUNT(c.id) FROM c WHERE c.Compliant = false) noncomp
JOIN(SELECT VALUE COUNT(c.id) FROM c WHERE c.Compliant = null) nullcomp
WHERE c.Period = 201950
GROUP BY c.HerdProfileId
ORDER BY NonCompliant DESC) cr
WHERE cr.NonCompliant > 0
results in: ORDER BY' is not supported in presence of GROUP BY
Is there any way to get the data needed or is this just not possible in Cosmos DB and do I need to order the results in code later on?
The first sql: Order by item expression could not be mapped to a document path. Please refer to the statements in this blog:
The second sql:
Order by can't work with Group By so far,please refer to official statement:
I suppose that you have to follow the suggestions in my previous case:How to group by and order by in cosmos db? you order the results in code so far. Waiting for the plan of above 2rd statement for group by and order by...
Problem description
I'm using sqlalchemy (v1.2) declarative, and I have a simple class Node with an id and a label. I would like to build a self-referencing many-to-many relationship where the association table is not a database table, but a dynamic select statement. This statement selects from two joined aliases of Node and returns rows of the form (left_id, right_id), defining the relationship. The code I have so far works if I access the relationship through an instance object, but when I try to filter by the relationship the joins are messed up.
The "classical" self-referential many-to-many relation
For reference, let's start with the example from the documentation on Self-Referential Many-to-Many Relationship, which uses an association table:
node_to_node = Table(
"node_to_node", Base.metadata,
Column("left_node_id", Integer, ForeignKey("node.id"), primary_key=True),
Column("right_node_id", Integer, ForeignKey("node.id"), primary_key=True)
)
class Node(Base):
__tablename__ = 'node'
id = Column(Integer, primary_key=True)
label = Column(String, unique=True)
right_nodes = relationship(
"Node",
secondary=node_to_node,
primaryjoin=id == node_to_node.c.left_node_id,
secondaryjoin=id == node_to_node.c.right_node_id,
backref="left_nodes"
)
def __repr__(self):
return "Node(id={}, Label={})".format(self.id, self.label)
Joining Node to itself through this relationship:
>>> NodeAlias = aliased(Node)
>>> print(session.query(Node).join(NodeAlias, Node.right_nodes))
SELECT node.id AS node_id, node.label AS node_label
FROM node JOIN node_to_node AS node_to_node_1
ON node.id = node_to_node_1.left_node_id
JOIN node AS node_1
ON node_1.id = node_to_node_1.right_node_id
Everything looks well.
The many-to-many relation through an association select statement
As an example we implement a relationship next_two_nodes which connects a node to the two nodes with id+1 and id+2 (if existent). The complete code for testing.
Here is a function which generates the select statement for the "dynamic" association table:
_next_two_nodes = None
def next_two_nodes_select():
global _next_two_nodes
if _next_two_nodes is None:
_leftside = aliased(Node, name="leftside")
_rightside = aliased(Node, name="rightside")
_next_two_nodes = select(
[_leftside.id.label("left_node_id"),
_rightside.id.label("right_node_id")]
).select_from(
join(
_leftside, _rightside,
or_(
_leftside.id + 1 == _rightside.id,
_leftside.id + 2 == _rightside.id
)
)
).alias()
return _next_two_nodes
Note that the function caches the result in a global variable, so that successive calls always return the same object instead of using new aliases. Here is my attempt to use this select in a relationship:
class Node(Base):
__tablename__ = 'node'
id = Column(Integer, primary_key=True)
label = Column(String, unique=True)
next_two_nodes = relationship(
"Node", secondary=next_two_nodes_select,
primaryjoin=(lambda: foreign(Node.id)
== remote(next_two_nodes_select().c.left_node_id)),
secondaryjoin=(lambda: foreign(next_two_nodes_select().c.right_node_id)
== remote(Node.id)),
backref="previous_two_nodes",
viewonly=True
)
def __repr__(self):
return "Node(id={}, Label={})".format(self.id, self.label)
Some test data:
nodes = [
Node(id=1, label="Node1"),
Node(id=2, label="Node2"),
Node(id=3, label="Node3"),
Node(id=4, label="Node4")
]
session.add_all(nodes)
session.commit()
Accessing the relationship through an instance works as expected:
>>> node = session.query(Node).filter_by(id=2).one()
>>> node.next_two_nodes
[Node(id=3, Label=Node3), Node(id=4, Label=Node4)]
>>> node.previous_two_nodes
[Node(id=1, Label=Node1)]
However, filtering on the relationship does not give the expected result:
>>> session.query(Node).join(NodeAlias, Node.next_two_nodes).filter(NodeAlias.id == 3).all()
[Node(id=1, Label=Node1),
Node(id=2, Label=Node2),
Node(id=3, Label=Node3),
Node(id=4, Label=Node4)]
I would expect only Node1 and Node2 to be returned. And indeed, the SQL statement of the join is wrong:
>>> print(session.query(Node).join(NodeAlias, Node.next_two_nodes))
SELECT node.id AS node_id, node.label AS node_label
FROM node JOIN (SELECT leftside.id AS left_node_id, rightside.id AS right_node_id
FROM node AS leftside JOIN node AS rightside
ON leftside.id + 1 = rightside.id OR leftside.id + 2 = rightside.id) AS anon_1
ON anon_1.left_node_id = anon_1.left_node_id
JOIN node AS node_1 ON anon_1.right_node_id = node_1.id
Comparing with the working example above, instead of ON anon_1.left_node_id = anon_1.left_node_id it should clearly read ON node.id = anon_1.left_node_id. My primaryjoin seems to be wrong, but I cannot figure out how to connect the last dots.
After more debugging I found that "Clause Adaption" is replacing my ON clause. I'm not sure about the details, but for some reasen sqlalchemy thinks that I am referring to the node.id from the select rather than from the original Node table. The only way I found to suppress clause adaption was to select in text form:
select(
[literal_column("leftside.id").label("left_node_id"),
literal_column("rightside.id").label("right_node_id")]
)...
This way the relationship to Node is broken and filtering works as expected. It feels like a hack with unforeseeable side effects, maybe someone knows a cleaner way...
I am newbie to Python.
I have 2 dictionaries which have the same keys but some keys have different values.
I would like to Iterate over the first dictionary and find the equal key In the second dictionary, check to see If the values equal and If not then print both values.
Can someone please help me with a template I can use?
Thanks
Iterate over one and compare the values.
dict2 = {"key1":"value1",
"key2":"value3"}
dict1 = {"key1":"value1",
"key2":"value2"}
for key in dict1:
if dict1[key] != dict2[key]:
print(key,dict1[key],dict2[key])
dict1 = {"key1": "value1", "key2": "value2", "key3": "value4"}
dict2 = {"key1": "value1", "key2": "value3"}
for key, value1 in dict1.items():
try:
value2 = dict2[key]
if value1 != value2:
print(key, value1, value2)
except KeyError:
print(key, value1, None)