How to get a node using index - neo4j

I have an entity Place:
#NodeEntity
#TypeAlias(value="Place")
public class Place implements Serializable{
private static final long serialVersionUID = 1L;
#GraphId
private Long nodeId;
#JsonProperty("id")
#Indexed(unique=true)
private String id;
//...
}
And I try to get a node based on its id attribute this way:
String pfc = "1234";
(Node)template.getIndex(Place.class, "id").get("id", pfc).getSingle()
But I'm having this exception :
java.lang.IllegalStateException: Index name for class java.lang.String id rel: false idx: true must differ from the default name: Place
Must I necessairly add a name to the index?
If yes, how should I do for the existent data?

Which version are you using? In SDN 3.x for Neo4j 2.x the indexes and constraints are used automatically.
I would use a PlaceRepository with a findById() method.
Or in general cypher queries that access place like this:
MATCH (p:Place {id:{id}})-->(x)
RETURN x
You can access them manually with template.merge() or template.findByLabelAndProperty() which I would only recommend when you know what you're doing.

Related

Neo4j Error | List<MyObject> | error- org.neo4j.ogm.exception.core.InvalidPropertyFieldException

I have a neo4j database, and one of the nodes in the database has the following:
public class Location
{
.
.
.
#Property(name = "zone_quantities")
private List<ZoneQuantity> zoneQuantityList;
}
When I try to use ogm to map the node into the object, I get the following error:
Caused by: org.neo4j.ogm.exception.core.InvalidPropertyFieldException: 'com.livspace.atp.domain.InvSku#zoneQuantityList' is not persistable as property but has not been marked as transient.
Neo4j version - 3.1.6
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
public class ZoneQuantity {
private String zone;
private Integer quantity;
}
Neo4j-OGM does not know what to do with the custom type property ZoneQuantity.
It is either a relationship and has to get described as such e.g.
#Relationship("HAS_ZONE")
private List<ZoneQuantity> zoneQuantityList;
or you need to provide an AttributeConverter for your custom type (collection) that converts it into a database compatible type. For example something like this converter https://github.com/neo4j/neo4j-ogm/blob/master/core/src/main/java/org/neo4j/ogm/typeconversion/NumberCollectionStringConverter.java#L37

MappingException(Attempt to add id) after upgrading to spring boot 2.2.X

After upgrading the spring boot to 2.2.4 (from 2.1.x), org.springframework.cloud:spring-cloud-dependencies to Hoxton.RELEASE and org.springframework.cloud:spring-cloud-stream-dependencies to Horsham.RELEASE.
Getting the following exception when trying to create index document.
Caused by: org.springframework.data.mapping.MappingException: Attempt to add id property private java.util.Map .CatalogIndex.document but already have property private java.lang.String .CatalogIndex.id registered as id. Check your mapping configuration!
Please find the entity class hierarchy. I have removed all the getter and setter for simplicity.
package mypackage.entity;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Parent;
import java.util.Date;
import java.util.List;
import java.util.Map;
public class CatalogIndex {
private static final long serialVersionUID = 1L;
#Id
private String id;
#Parent(type = "Initiative")
private String initiativeId;
private List<Map<String, Object>> typeHierarchy;
private Map<String, Object> document;
private List<Map<String, Object>> filters;
}
package mypackage.entity;
import org.springframework.data.elasticsearch.annotations.Document;
#Document(indexName = "cataloginitiative")
public class CatalogInitiativeIndex extends CatalogIndex { }
Spring Data Elasticsearch, when inspecting the Entity class, tries to figure out which property of the class is to be used as the Id property. A property qualifies for this if one of the following is true:
the property is annotated with #Id
the property is named id
the property is named document
So in your case you have the property id which has a matching name and the annotation, and the property document with a matching name.
You have to rename your property document to somthing different.

SpringData Cassandra Java Adapter - Using UDTs in Map Columns

I am using the 1.5.1 version of the Cassandra adapter for Java, and I am attempting to insert a record to a table having a Map column that uses a UDT as the column value (key is just a varchar). I created the table using cqlsh and am able to insert to it in CQL just fine. When i try to use a CassandraTemplate...insert(), though, all I get is:
UserTypeResolver must not be null
My UDT class is defined as:
#UserDefinedType("iss_type")
public class IssueType {
#CassandraType(type = DataType.Name.VARCHAR)
private String issue_code;
#CassandraType(type = DataType.Name.VARCHAR)
private String issue_name;
#CassandraType(type = DataType.Name.TIMESTAMP)
private Date issue_start;
#CassandraType(type = DataType.Name.TIMESTAMP)
private Date issue_end;
And my table is defined as
#Table
public class IssueMap {
#PrimaryKeyColumn(
type = PrimaryKeyType.PARTITIONED)
private UUID map_id;
#Column
private Map<String, IssueType> issue_map;
In my config, i have:
#Bean
public CassandraMappingContext cassandraMapping()
throws ClassNotFoundException {
BasicCassandraMappingContext mappingContext = new BasicCassandraMappingContext();
mappingContext.setUserTypeResolver(new SimpleUserTypeResolver(cluster().getObject(),"campaign_management"));
return mappingContext;
}
Is there something I am missing here? Or is it just not possible to define columns this way? I realize I could just use a query builder to create the CQL and do the insert, but I was hoping to be able to make full use of the Cassandra template features.

How to use exists, findOne and other GraphRepository methods, taking id as argument?

Let us assume following:
1). We have two entities:
#NodeEntity
public class A {
#GraphId
private Long id;
...
}
#NodeEntity
public class B {
#GraphId
private Long id;
...
}
2). We have two appropriate repositories:
public interface ARepository extends GraphRepository<A> {
...
}
public interface BRepository extends GraphRepository<B> {
...
}
3). And we have following nodes in database:
A with id=1
B with id=2
Case a: Now assume we need to check whether A with id=2 is exists:
ARepository.exists(2)
I expect that it will return false, since A with id=2 isn't exists. But it returns true, since it tries to find among all ids, not only among A nodes.
Case b: Or maybe we need to find B with id=1:
BRepository.findOne(1);
I expect that it returns null or throws appropriate exception, informing that B with id=1 isn't exists. But it throws unexpected for me PersistentEntityConversionException.
Hence questions:
How can we use aforementioned operations with expected behavior?
May be there is workaround?

Spring Data Neo4j neo4jTemplate.fetch() only returns one value

I'm converting a working system that uses #Fetch to a lazy load strategy. However, when I retrieve the object with a container, the container only has one entry and neo4jTemplate.fetch(obj.getContainer()) does not retrieve the other entries.
Here are the pertinent snippets
#NodeEntity
public class SourcePage {
#GraphId
private Long id;
#RelatedTo(type = "GROUP_MEMBER")
private Group group;
Group Class:
#NodeEntity
public class Group {
#GraphId
private Long id;
#RelatedTo(type = "GROUP_MEMBER", direction = Direction.INCOMING)
private Set<SourcePage> sourcePages = new HashSet<>();
Test Code:
Group group1 = groupRepository.findByName("Test Group");
neo4jTemplate.fetch(group1.getSourcePages());
assertThat(group1.getSourcePages().size(), is(254));
The Result:
java.lang.AssertionError:
Expected: is <254>
but: was <1>
If I do nothing but add #Fetch to private Group group, then it all works as expected.
Also, I looked at the database server with only this test example and ran this query:
MATCH (a)-[:`GROUP_MEMBER`]->(b) RETURN count(b)
It returned 254 as expected. I have also tried direction.BOTH on each side of the relationship - same results.
I found the problem. It's esoteric and plausible enough that it might help someone else seeing the same symptom.
First, I didn't show that I had my own hashCode() for SourcePage. It hashed a field defined as:
#NotEmpty
#Indexed
private String url;
Without #Fetch the 'url' is not retrieved automatically, so all the SourcePages in the container have the same hash code. This resulted in 100% collisions and only one entry added to the set.
If I removed the hashCode() then the default hash worked and all the objects were added to the set.
After several hours of debugging, I posted my question. Of course right after that I stumbled on the solution.
Moral of the story: don't provide a hash function on member data without the ID.

Resources