I have users 1 and 7 and I want to merge a relationship friend between them.The cypher query works fine but when i try to write it in java it is not working
how to do this cypher query using java:
MATCH (a:user), (b:user)
WHERE a.ID="1" AND b.ID="7"
Merge (a)-[:friend]->(b)
return a, b
I tried to this but it is not working
Result result = db.execute( "MERGE (a:user {ID:'7'})-[:friend]->(b:user {ID:'5'}) return a.ID,b.ID") )
also I tried this
Result result = db.execute(MATCH (a:user), (b:user) WHERE a.ID='1' AND b.ID='7' Merge (a)-[: friend]->(b) return a, b)
Both are not working
You have several Java syntax errors.
The first statement has an extra ) at the end. It also needs to end with a semicolon.
the seconds statement needs to wrap the Cypher query in double-quotes (to be a legal Java String). It also needs to end with a semicolon.
Here is complete code snippet that should work in your case:
try (Transaction tx = db.beginTx()) {
// Query, with params
String query = "MATCH (a:user {ID: {aId}}), (b:user {ID: {bId}}) " +
"MERGE (a)-[:friend]->(b) " +
"RETURN a, b";
// Params
Map<String, Object> params = new HashMap<>();
params.put("aId", 1);
params.put("bId", 7);
// Execute in try-with-resource, to ensure that result will be closed
try (Result result = db.execute(query, params)) {
// read result here
}
tx.success();
}
Notable things here:
Transaction is executed in try-with-resource block
Query is using params - {aId} and {bId}
Params are passed as Map with query to database
Query ix executed in try-with-resource block, to ensure that resource will be closed
Probably you should checkout Using Neo4j from Java developer resources, to get more examples and information on that topic.
Related
I call the count aggregate function in my service class using JOOQ.
SelectQuery<Record> query = this.dsl.selectQuery();
query.addSelect(DSL.count());
query.addFrom(SOME_TABLE);
final Integer total = query.fetchOne(0, Integer.class);
I need to mock count result in my unit test.
What is the best way to do that?
Following jooq documentation, I have to create result record with relevant fields count.
Something like that:
Result<Record1<Integer>> result = create.newResult(...);
But what I have to use as the create.newResult() method parameters in case of creating the mock record for aggregate function?
Your query should return one row with one column, so create that result:
Field<Integer> c = DSL.count();
Result<Record1<Integer>> result = create.newResult(c);
result.add(create.newRecord(c).values(42));
The documentation you've linked shows a very similar example:
...
// You decide, whether any given statement returns results, and how many
else if (sql.toUpperCase().startsWith("SELECT")) {
// Always return one record
Result<Record2<Integer, String>> result = create.newResult(AUTHOR.ID,AUTHOR.LAST_NAME);
result.add(create
.newRecord(AUTHOR.ID, AUTHOR.LAST_NAME)
.values(1, "Orwell"));
mock[0] = new MockResult(1, result);
}
...
Here is a query that I want to try out in MySQL
SELECT A.x
FROM A
WHERE A.y = 'P'
UNION
SELECT A.x
FROM A
WHERE A.y = 'Q'
The above is a cut-down, much simpler version of the original query that I am trying. In my original query, each SELECT statement involves multiple tables with INNER JOIN
If the possible number of values in 'y' column of table 'A' that I need to query upon is 'n', then my query will involve doing 'n-1' unions on 'n' SELECT statements
I know that JOOQ can do union of multiple SELECT statements. But is there a good way to do this post Java 8 style? maybe using Steam.collect()?
This is what I have but wondering if I could do better
String firstValueToQuery = valuesToQuery.get(0);
Select<Record5<UUID, UUID, String, Integer, String>> selectQuery = getSelectQueryForValue(firstValueToQuery);
valuesToQuery.stream()
.skip(1)
.forEach(valueToQuery -> selectQuery.unionAll(getSelectQueryForValue(valueToQuery)));
selectQuery.fetchStream();
Here is how I implement getSelectQueryForValue
private Select<Record5<UUID, UUID, String, Integer, String>> getSelectQueryForValue(String valueToQuery) {
return jooq.select(
A.P,
A.Q,
A.R,
A.S,
A.T)
.from(A)
.where(A.Y.eq(valueToQuery));
}
PS: I understand that I could rather use the 'IN' clause like below
SELECT A.x
FROM A
WHERE A.y IN ('P','Q',...)
But with my current data distribution in the database, MySQL is using a sub-optimal query plan. Thus using UNION so that the database implicitly prefers a faster query plan by making use of the right index
The idiomatic approach here would be as follows (using JDK 9 API):
try (Stream<Record5<UUID, UUID, String, Integer, String>> stream = valuesToQuery
.stream()
.map(this::getSelectQueryForValue)
.reduce(Select::union)
.stream() // JDK 9 method
.flatMap(Select::fetchStream)) {
...
}
It uses the useful Optional.stream() method, which was added in JDK 9. In JDK 8, you could do this instead:
valuesToQuery
.stream()
.map(this::getSelectQueryForValue)
.reduce(Select::union)
.ifPresent(s -> {
try (Stream<Record5<UUID, UUID, String, Integer, String>> stream =
s.fetchStream()) {
...
}
})
I blogged about this in more detail here.
I have a predicate(javax.persistence.criteria.Predicate) which filters raw data as follows:
public Predicate byAccountsId(Collection<Long> accountsId) {
ParameterExpression<?> param = createParam(AOraArrayUserType.class, new AOraArrayUserType(accountsId));
return criteriaBuilder().or(
criteriaBuilder()
.equal(criteriaBuilder().function("in_ex", Long.class, actSourceJoin().get(Account_.id),
param), 1),
criteriaBuilder().equal(
criteriaBuilder().function("in_ex", Long.class, actDestinationJoin().get(Account_.id),
param), 1));
}
This predicate builds the next part of the query:
..
where
..
act.source_id in (accountsId.values())
or act.destination_id in (accountsId.values() - array ids)
..
It works fine but there may be too much raw data.I want to use "Oracle functional index", which removes unnecessary data from the query results. I tried to rewrite my predicate as follows:
public Predicate byAccountsId(Collection<Long> accountsId) {
ParameterExpression<?> param = createParam(AOraArrayUserType.class, new AOraArrayUserType(accountsId));
return criteriaBuilder().or(
criteriaBuilder().literal(
Restrictions.sqlRestriction("case when state != 'ARCHIVE' then source_id else null end"))
.in(param));
}
Resurlt query builds fine but returns no result. But when I copy result query to sql developer and run the query it returns the expected result.
Part of the query which is build by new predicate:
..
where
..
(case when act.state != 'ARCHIVE' then act.source_id else null end) in (accountsId.values() - array ids)
..
Does anybody know why I don't get the correct result when I'm using the new predicate?
And can I use hibernate.criterion.Restrictions with javax.persistence.criteria.Predicate?
You can define #Formula for the expression in your Entity (AOraArrayUserType) and use the field in criteria
Restrictions.in("theFormulaField", param)
I have just started using Mongo Db . Below is my data structure .
It has an array of skillID's , each of which have an array of activeCampaigns and each activeCampaign has an array of callsByTimeZone.
What I am looking for in SQL terms is :
Select activeCampaigns.callsByTimeZone.label,
activeCampaigns.callsByTimeZone.loaded
from X
where skillID=50296 and activeCampaigns.campaign_id= 11371940
and activeCampaigns.callsByTimeZone='PT'
The output what I am expecting is to get
{"label":"PT", "loaded":1 }
The Command I used is
db.cd.find({ "skillID" : 50296 , "activeCampaigns.campaignId" : 11371940,
"activeCampaigns.callsByTimeZone.label" :"PT" },
{ "activeCampaigns.callsByTimeZone.label" : 1 ,
"activeCampaigns.callsByTimeZone.loaded" : 1 ,"_id" : 0})
The output what I am getting is everything under activeCampaigns.callsByTimeZone while I am expecting just for PT
DataStructure :
{
"skillID":50296,
"clientID":7419,
"voiceID":1,
"otherResults":7,
"activeCampaigns":
[{
"campaignId":11371940,
"campaignFileName":"Aaron.name.121.csv",
"loaded":259,
"callsByTimeZone":
[{
"label":"CT",
"loaded":6
},
{
"label":"ET",
"loaded":241
},
{
"label":"PT",
"loaded":1
}]
}]
}
I tried the same in Java.
QueryBuilder query = QueryBuilder.start().and("skillID").is(50296)
.and("activeCampaigns.campaignId").is(11371940)
.and("activeCampaigns.callsByTimeZone.label").is("PT");
BasicDBObject fields = new BasicDBObject("activeCampaigns.callsByTimeZone.label",1)
.append("activeCampaigns.callsByTimeZone.loaded",1).append("_id", 0);
DBCursor cursor = coll.find(query.get(), fields);
String campaignJson = null;
while(cursor.hasNext()) {
DBObject campaignDBO = cursor.next();
campaignJson = campaignDBO.toString();
System.out.println(campaignJson);
}
the value obtained is everything under callsByTimeZone array. I am currently parsing the JSON obtained and getting only PT values . Is there a way to just query the PT fields inside activeCampaigns.callsByTimeZone .
Thanks in advance .Sorry if this question has already been raised in the forum, I have searched a lot and failed to find a proper solution.
Thanks in advance.
There are several ways of doing it, but you should not be using String manipulation (i.e. indexOf), the performance could be horrible.
The results in the cursor are nested Maps, representing the document in the database - a Map is a good Java-representation of key-value pairs. So you can navigate to the place you need in the document, instead of having to parse it as a String. I've tested the following and it works on your test data, but you might need to tweak it if your data is not all exactly like the example:
while (cursor.hasNext()) {
DBObject campaignDBO = cursor.next();
List callsByTimezone = (List) ((DBObject) ((List) campaignDBO.get("activeCampaigns")).get(0)).get("callsByTimeZone");
DBObject valuesThatIWant;
for (Object o : callsByTimezone) {
DBObject call = (DBObject) o;
if (call.get("label").equals("PT")) {
valuesThatIWant = call;
}
}
}
Depending upon your data, you might want to add protection against null values as well.
The thing you were looking for ({"label":"PT", "loaded":1 }) is in the variable valueThatIWant. Note that this, too, is a DBObject, i.e. a Map, so if you want to see what's inside it you need to use get:
valuesThatIWant.get("label"); // will return "PT"
valuesThatIWant.get("loaded"); // will return 1
Because DBObject is effectively a Map of String to Object (i.e. Map<String, Object>) you need to cast the values that come out of it (hence the ugliness in the first bit of code in my answer) - with numbers, it will depend on how the data was loaded into the database, it might come out as an int or as a double:
String theValueOfLabel = (String) valuesThatIWant.get("label"); // will return "PT"
double theValueOfLoaded = (Double) valuesThatIWant.get("loaded"); // will return 1.0
I'd also like to point out the following from my answer:
((List) campaignDBO.get("activeCampaigns")).get(0)
This assumes that "activeCampaigns" is a) a list and in this case b) only has one entry (I'm doing get(0)).
You will also have noticed that the fields values you've set are almost entirely being ignored, and the result is most of the document, not just the fields you asked for. I'm pretty sure you can only define the top-level fields you want the query to return, so your code:
BasicDBObject fields = new BasicDBObject("activeCampaigns.callsByTimeZone.label",1)
.append("activeCampaigns.callsByTimeZone.loaded",1)
.append("_id", 0);
is actually exactly the same as:
BasicDBObject fields = new BasicDBObject("activeCampaigns", 1).append("_id", 0);
I think some of the points that will help you to work with Java & MongoDB are:
When you query the database, it will return you the whole document of
the thing that matches your query, i.e. everything from "skillID"
downwards. If you want to select the fields to return, I think those will only be top-level fields. See the documentation for more detail.
To navigate the results, you need to know that a DBObjects are returned, and that these are effectively a Map<String,
Object> in Java - you can use get to navigate to the correct node,
but you will need to cast the values into the correct shape.
Replacing while loop from your Java code with below seems to give "PT" as output.
`while(cursor.hasNext()) {
DBObject campaignDBO = cursor.next();
campaignJson = campaignDBO.get("activeCampaigns").toString();
int labelInt = campaignJson.indexOf("PT", -1);
String label = campaignJson.substring(labelInt, labelInt+2);
System.out.println(label);
}`
I have noticed that you can pass "params" straight in to the boilerplate code below:
[fooInstanceList: Foo.list(params), fooInstanceTotal: Foo.count()]
Is it possible to pass "params" in as part of a Hibernate criteria for example the one below?
def c = Foo.createCriteria()
def results = c {
not { eq("bar","test") }
}
[fooInstanceList: results, fooInstanceTotal: results.size()]
I am looking to use the "max" and "offset" params so I can use it for paging for example. I would also like to use the equivalent of count that counts all non-paged results. I think results.size() would only give me paged results, instead of the desired non-paged results. How would I go about this?
You can use params while using the criteria. I suppose you have a typo of not using c.list
def c = Foo.createCriteria()
def results = c.list(params) {
not { eq("bar","test") }
}
Assuming params has max and offset.
Criteria returns a PagedResultList where you can get the totalCount from it. So
results.totalCount //results.getTotalCount()
should give you the total count, although there is always a second query fired to get the total count. In this case Hibernate does that for you instead of you doing it explicitly.