Datanucleus mongodb references - mongodb

Can I fetch fields by DBRef?
I have to separate collection mapped to:
#PersistenceCapable(table = "group")
public class MyGroup
{
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY, column = "_id")
private String id;
private String name;
private Person person;
// getters/setters
...
}
#PersistenceCapable(table = "people")
public class Person
{
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY, column = "_id")
private String id;
private String firstName;
private String lastName;
// getters/setters
...
}
I'd like to get person name (currently I got person as null):
MyGroup myGroup = persistenceManager.getObjectById(MyGroup.class, "5230a918ac8c95fd3d9a3dfa")
myGroup.getPerson().getFirstName();
and perform queries:
Query query = persistenceManager.newQuery(MyGroup.class);
query.setFilter("persone.firstName == \"Tester\"");

DataNucleus doesn't support DBRef on MongoDB datastore:
http://www.datanucleus.org/servlet/forum/viewthread_thread,7924#38188

Related

Spring Data MongoDB not able to load reference collection (#DocumentReference)

In Spring data findAll method reference object is coming as null
I am using Reactive Mongo Repository
Ex Parent Object
#Data
#Document(collection = "country")
public class CountryBean {
#Id
private String id;
private String name;
}
Child Object
#Document(collection = "city")
public class CityBean {
#Id
private String id;
#Field(name = "name")
private String name;
#Field(name = "city_code")
private String cityCode;
#Field(name = "show_city")
private boolean showCity;
#DocumentReference(lazy = false)
private StateBean state;
}
Country Collection
State Collection (Here we can see the country Attribute)
But When trying to fetch from DB, I am getting country attribute as null. Tried both lazy true/false, but not getting country object along with state object.
#GetMapping("/get-all-state")
Flux<StateBean> allState() {
Flux<CountryBean> ct = countryRepository.findAll();
Flux<StateBean> bean= stateRepository.findByCountry(ct.blockFirst());
return bean;
}
[{"id":"6237a912850ceb6261998a53","name":"Bangalore","statecode":"39","country":null},{"id":"6237a94a850ceb6261998a55","name":"delhi","statecode":"39","country":null}]

How to build nested object using criteriaBuilder.construct in JPA Criteria Query

I want to query the list of the phone with the person as a phone DTO object but while I construct a DTO object it provides an error.
Phone Entity:
public class Phone {
#Id
#GeneratedValue
private Long id;
private String number;
#Enumerated(EnumType.STRING)
private PhoneType type;
#ManyToOne
#JoinColumn(name = "person_id")
private Person person;
}
Person Entity:
public class Person {
#Id
#GeneratedValue
private long id;
private String name;
private String nickName;
private String address;
private LocalDateTime createdAt;
#Version
private int version;
#OneToMany(mappedBy = "person" cascade = CascadeType.ALL)
private List<Phone> phones;
}
Phone DTO:
public class PhoneDTO {
private Long id;
private String number;
private PhoneType type;
private PersonDTO person;
}
Person DTO:
public class PersonDTO {
private long id;
private String name;
private String nickName;
private String address;
private LocalDateTime createdAt;
private int version;
}
Criteria query:
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<PhoneDTO> criteriaQuery = builder.createQuery(PhoneDTO.class);
Root<Phone> root = criteriaQuery.from(Phone.class);
Join<Phone, Person> person = root.join("person");
Path<Object> id = root.get("id");
Path<Object> number = root.get("number");
Path<Object> type = root.get("type");
Path<Object> personId = person.get("id");
Path<Object> name = person.get("name");
Path<Object> nickName = person.get("nickName");
Path<Object> address = person.get("address");
Path<Object> createdAt = person.get("createdAt");
Path<Object> version = person.get("version");
criteriaQuery.select(builder.construct(PhoneDTO.class, id, number, type, builder.construct(PersonDTO.class, personId, name, nickName, address, createdAt, version)));
TypedQuery<PhoneDTO> query = em.createQuery(criteriaQuery);
How to do this??
criteriaQuery.select(builder.construct(PhoneDTO.class, id, number, type, builder.construct(PersonMediumDTO.class, personId, name, nickName, address, createdAt, version)));
How to construct a nested object??

Spring data MongoDB match, lookup and projection to select only required field from looked-up document

I have below two Document structures. In the structure CRMContact.orgGroupId == OrganizationGroup.id. I would like to fetch all the CRMContact document that matches with sharedGroupIds and also select only a few fields from CRMContact and only OrganizationGroup.groupownername from OrganizationGroup and match/populate groupId (with only one field [groupownername] populated). I have used below custom implementation but didn't work.
I have included aggregarionsNotWorking which is not working and aggregarions returning entire OrganizationGroup populated. How to achieve this i.e. just to populate groupownername field, using spring data mongodb?
#Document(collection = "ww_crm_contact")
public class CRMContact{
#Id
protected String id;
private String displayName;
private String firstName;
private String middleName;
private String lastName;
private OrganizationGroup groupId; //Ignore //Modified field name orgGroupId
#Indexed(name = "CRMCONTACT_SHAREDGROUPID_IDX",background = true)
private List<String> sharedGroupIds = new LinkedList<>();
#Indexed(name = "CRMCONTACT_ORGGROUPID_IDX",background = true)
private String orgGroupId;
}
#Document(collection = "ww_organization_groups")
public class OrganizationGroup {
private static final long serialVersionUID = 600049975643062552L;
#Id
protected String id;
private String groupName;
private int riaId;
private Boolean isPrivate;
private String description;
private Boolean deleted;
#Transient
private int count;
private String groupownerid;
private String groupownername;
}
#Repository
public class CustomCRMContactDAO {
#Autowired
MongoTemplate mongoTemplate;
public List<CRMContact> getContactsPresentInGroup(List<ObjectId> objectIds){
LookupOperation lookupOperation = LookupOperation.newLookup().from("ww_organization_groups").localField("orgGroupId").foreignField("_id").as("groupId");
ProjectionOperation fields = project("firstName","lastName", "primaryId","displayName","groupId.groupownername");
Aggregation aggregarionsNotWorking = Aggregation.newAggregation(Aggregation.match(Criteria.where("sharedGroupIds").in(objectIds)),lookupOperation,unwind("groupId"),fields); //Not Working even if I change the field only to groupownername
Aggregation aggregarions = Aggregation.newAggregation(Aggregation.match(Criteria.where("sharedGroupIds").in(objectIds)),lookupOperation,fields); //
List<CRMContact> crmContacts = mongoTemplate.aggregate(aggregarions, "ww_crm_contact",CRMContact.class).getMappedResults();
return crmContacts;
}
}

How to use a #ConstructorResult with a Set<SomeEnum> field

I'm trying to create a #NamedNativeQuery with a #ConstructorResult for a class that has a field with a Set of enum values.
VeterinarianJPA.java:
#Entity
#Table(name = "veterinarians")
#Setter
#Getter
#NoArgsConstructor
#NamedNativeQueries({
#NamedNativeQuery(
name = VeterinarianJPA.FIND_ALL_VETS,
query = "SELECT v.id, v.name, vs.specialisations " +
"FROM veterinarians v " +
"JOIN veterinarian_specialisations vs ON v.id = vs.vet_id",
resultSetMapping = VeterinarianJPA.VETERINARIAN_RESULT_MAPPER
)})
#SqlResultSetMappings({
#SqlResultSetMapping(
name = VeterinarianJPA.VETERINARIAN_RESULT_MAPPER,
classes = #ConstructorResult(
targetClass = Veterinarian.class,
columns = {
#ColumnResult(name = "id", type = Long.class),
#ColumnResult(name = "name"),
#ColumnResult(name = "specialisations", type = Set.class)
}
)
)})
class VeterinarianJPA {
static final String FIND_ALL_VETS = "net.kemitix.naolo.gateway.data.jpa.findAllVets";
static final String VETERINARIAN_RESULT_MAPPER = "net.kemitix.naolo.gateway.data.jpa.Veterinarian";
#Id
#GeneratedValue
private Long id;
private String name;
#ElementCollection
#Enumerated(EnumType.STRING)
#CollectionTable(
name = "veterinarian_specialisations",
joinColumns = #JoinColumn(name = "vet_id")
)
private final Set<VetSpecialisation> specialisations = new HashSet<>();
}
Veterinarian.java:
public final class Veterinarian {
private Long id;
private String name;
private Set<VetSpecialisation> specialisations;
public Veterinarian() {
}
public Veterinarian(final long id,
final String name,
final Set<VetSpecialisation> specialisations) {
this.id = id;
this.name = name;
this.specialisations = new HashSet<>(specialisations);
}
public long getId() {
return id;
}
public String getName() {
return name;
}
public Set<VetSpecialisation> getSpecialisations() {
return new HashSet<>(specialisations);
}
}
VetSpecialisation.java:
public enum VetSpecialisation {
RADIOLOGY,
DENTISTRY,
SURGERY
}
When I attempt to execute the named query:
entityManager.createNamedQuery(VeterinarianJPA.FIND_ALL_VETS, Veterinarian.class)
.getResultStream()
I get the following exception:
java.lang.IllegalArgumentException: Could not locate appropriate constructor on class : net.kemitix.naolo.entities.Veterinarian
at org.hibernate.loader.custom.ConstructorResultColumnProcessor.resolveConstructor(ConstructorResultColumnProcessor.java:92)
at org.hibernate.loader.custom.ConstructorResultColumnProcessor.performDiscovery(ConstructorResultColumnProcessor.java:45)
at org.hibernate.loader.custom.CustomLoader.autoDiscoverTypes(CustomLoader.java:494)
at org.hibernate.loader.Loader.processResultSet(Loader.java:2213)
at org.hibernate.loader.Loader.getResultSet(Loader.java:2169)
at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1930)
at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1892)
at org.hibernate.loader.Loader.scroll(Loader.java:2765)
at org.hibernate.loader.custom.CustomLoader.scroll(CustomLoader.java:383)
at org.hibernate.internal.SessionImpl.scrollCustomQuery(SessionImpl.java:2198)
at org.hibernate.internal.AbstractSharedSessionContract.scroll(AbstractSharedSessionContract.java:1058)
at org.hibernate.query.internal.NativeQueryImpl.doScroll(NativeQueryImpl.java:217)
at org.hibernate.query.internal.AbstractProducedQuery.scroll(AbstractProducedQuery.java:1462)
at org.hibernate.query.internal.AbstractProducedQuery.stream(AbstractProducedQuery.java:1486)
at org.hibernate.query.Query.getResultStream(Query.java:1110)
I expect that the SQL is returning multiple rows for a multi-valued Set rather than a single value, which is causing the constructor not to match. How do I change the SQL to produce the correct input to the constructor, or is there another configuration change I need to make?
Well, I'm not sure if that's even possible in the way you want to to this. But you can use LISTAGG function on specialisations table to inline the specialisations with veterinarians by using some kind of separator.
So the query should look like this:
SELECT v.id, v.name
(SELECT LISTAGG(vs.type, ';')
WITHIN GROUP (ORDER BY vs.type)
FROM veterinarian_specialisations vs
WHERE vs.vet_id = v.id) specialisations
FROM veterinarians v;
The query will return veterinarian and his semicolon separated specialisations:
1 NAME DENTISTRY;RADIOLOGY
And then in your Veterinarian class constructor you must remap String result back to Set of VetSpecialisation. I used Java 8 stream api just for convenience.
public final class Veterinarian {
private Long id;
private String name;
private Set<VetSpecialisation> specialisations;
public Veterinarian() {
}
public Veterinarian(final long id,
final String name,
final String specialisations) {
this.id = id;
this.name = name;
this.specialisations = Arrays.asList(specialisations.split(";"))
.stream()
.map(VetSpecialisation::valueOf) //Map string to VetSpecialisation enum.
.collect(Collectors.toSet());
}

Querying Embedded document in MongoDB using Mongo Template

I have the above domain structure where I have list of Companies in the product and the aim is not make entry in mongoDB when I have exact match for companies & productId already present in the DB.
#Entity
public class Mobile {
#Id
private Integer id;
private String imei;
private Product productInfo;
// ...
}
#Entity
public class Product {
#Id
private Integer id;
private String productId;
private List<Company<?>> companies;
// ...
}
#JsonTypeInfo(use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY, property = "type")
#JsonSubTypes({
#JsonSubTypes.Type(name= "samsung", value = Samsung.class),
#JsonSubTypes.Type(name= "htc",value = Htc.class)})
public class Company<T> implements Serializable {
private static final long serialVersionUID = -8869676577723436716L;
private T companyInfo;
private String type;
// ...
}
I am using mongo template and I have tried to use find as shown below but id didn't work
template.find(Query.query(Criteria.where("product.companies").is(companList),Mobile.class);