Can I mark more than one field as #indexed in single document in MongoDb? - mongodb

I am using #indexed annotation in my document for the person while using spring boot and MongoDb.
I have already marked firstName to be used for indexing.
Can I mark other fields as well for index?
The document is as mentioned below:
#Document
public class Person {
#Id private String id;
#Indexed(name = "first_name_index", direction = IndexDirection.DESCENDING)
private String firstName;
private String secondName;
private LocalDateTime dateOfBirth
}
Is it a good practice to mark more than one field as indexed?

Yes. You can index multiple fields as #Indexed if your queries are orthogonal.
You need to support findByFirstName and findByDateOfBirth queries.
you add #Indexed annotation to firstName
you add #Indexed annotation to dateOfBirth
You need to support findByFirstName and findByFirstNameAndDateOfBirth queries.
you add #CompoundIndex(def = "{'findByFirstName': 1, 'dateOfBirth': 1}") to public class Person.

Related

Hibernate mapping camelCase field to snake_case

I am using hibernate with postgresql. I am curious if is it possible to map for example this entity:
#Entity
#Data
#NoArgsConstructor
class User {
#Id
private Long id;
private String firstName;
private String lastName;
}
in database I have columns like first_name, last_name. I got error that I introduce wrong names (when I add for example #Column(name = "first_name"); everything is ok. How can I avoid adding #Column neither change database?

How to retrieve #IndexedEmbedded properties?

FullTextQuery.setProjection("id", "author") ignored author's id, name property. How can I retrieve these properties?
#MappedSuperclass
class BaseContent{
#IndexedEmbedded(prefix = "author.", includePaths = {"id", "name"}) #ManyToOne
Author author;
}
#Entity #Indexed
class Content extends BaseContent{
#Id #DocumentId
Integer id;
}
#Entity
class Author{
#Id
Integer id;
#Field(store = Store.YES)
String name;
}
EDIT:
Is this query correct?.
FullTextQuery ftq = fullTextSession.createFullTextQuery(luceneQuery, Content.class);
ftq.setProjection("id", "author.id", "author.name");
ftq.setResultTransformer(new AliasToBeanResultTransformer(Content.class));
List<Content> result = ftq.list();
Use the author. prefix.
fullTextQuery.setProjection("author.id", "author.name")
EDIT: Did you try inspecting the results without your transformer? It should return a List<Object[]> with the content of the projections. If it does, then it's the transformer that isn't working. I very much doubt that AliasToBeanResultTransformer is able to handle composite aliases such as "author.name". You'll probably need you own transformer.
Also note that:
If you just want to get the Content entity, and getting it from the database doesn't bother you, just remove the projection and result transformer: Hibernate Search will get a List<Content> from the database for you.
If what you're trying to do is to avoid loading anything from the database, then you're on the right path. But as I said, you'll probably need a custom transformer.

Hibernate OGM mapping to subcollection

I have an collection as following
application
* _id
* name
* desc
* settings
** _id
** magento
*** name
*** keys
I use the following object to map the document
#Entity
#Table(name = "applications")
public class ApplicationEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Type(type = "objectid")
private String id;
#Column(name = "applicationName")
private String name;
#Column(name = "desc")
private String desc;
#Embedded
#Column(name = "settings.magento")
private MagentoSettings magentoSettings;
However, the object "MangetoSettings" could not be mapped and it return null.
My question is that how I can map sub document (magento) without declare the parent (settings) in my object?
Let's say the "Settings" document contains only "Magento" and it would be wasted if declare "Settings" object with single property.
Thanks
I found the answer in the Jboss Hibernate doc here
You can override the column name used for a property of an embedded object. But you need to know that the default column name is the concatenation of the embedding property, a . (dot) and the embedded property (recursively for several levels of embedded objects).
AttributeOverrides({
#AttributeOverride(name="name", column=#Column(name="settings.magento.name")),
#AttributeOverride(name="key", column=#Column(name="settings.magento.key"))
})
private MagentoSettings magentoSettings;
Thanks

Spring data mongodb: query and sort results based on difference of two fields

Say I have a Collection defined like bellow:
#Document(collection = "Item")
public class Item {
#Id
private String id;
private String title;
private String mrp;
private String discount;
//getters and setters goes here
}
I need to find all items which are sorted on [mrp - discount] value.
How to express this using MongoOperations
That's what the Aggregation Framework is for. Spring Data MongoDB offers aggregate via MongoOperations.
TypedAggregation<Item> agg = newAggregation(Item.class,
project()
.andExpression("mrp - discount").as("total")
.andInclude("mrp", "discount", "id"),
sort(new Sort(ASC, "total")));

JPA Query Many To One nullable relationship

I have the following entities and would like to seek help on how to query for selected attributes from both side of the relationship. Here is my model. Assume all tables are properly created in the db. JPA provider I am using is Hibernate.
#Entity
public class Book{
#Id
private long id;
#Column(nullable = false)
private String ISBNCode;
#ManyToOne(cascade = CascadeType.DETACH, fetch = FetchType.LAZY, optional = false)
private Person<Author> author;
#ManyToOne(cascade = CascadeType.DETACH, fetch = FetchType.LAZY, optional = true)
private Person<Borrower> borrower;
}
#Inheritance
#DiscriminatorColumn(name = "personType")
public abstract class Person<T>{
#Id
private long id;
#OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Info information;
}
#Entity
#DiscriminatorValue(PersonType.Author)
public class Author extends Person<Author> {
private long copiesSold;
}
#Entity
#DiscriminatorValue(PersonType.Borrower)
public class Borrower extends Person<Borrower> {
.....
}
#Entity
public class Info {
#Id
private long id;
#Column(nullable=false)
private String firstName;
#Column(nullable=false)
private String lastName;
......;
}
As you can see, the book table has a many to one relation to Person that is not nullable and Person that is nullable.
I have a requirement to show, the following in a tabular format -
ISBNCode - First Name - Last Name - Person Type
How can I write a JPA query that will allow me to select only attributes that I would want. I would want to get the attributes ISBN Code from Book, and then first and last names from the Info object that is related to Person Object that in turn is related to the Book object. I would not want to get all information from Info object, interested only selected information e.g first and last name in this case.
Please note that the relation between the Borrower and Book is marked with optional=true, meaning there may be a book that may not have been yet borrowed by someone (obviously it has an author).
Example to search for books by the author "Marc":
Criteria JPA Standard
CriteriaQuery<Book> criteria = builder.createQuery( Book.class );
Root<Book> personRoot = criteria.from( Book.class );
Predicate predicate = builder.conjunction();
List<Expression<Boolean>> expressions = predicate.getExpressions();
Path<Object> firtsName = personRoot.get("author").get("information").get("firstName");
expressions.add(builder.equal(firtsName, "Marc"));
criteria.where( predicate );
criteria.select(personRoot);
List<Book> books = em.createQuery( criteria ).getResultList();
Criteria JPA Hibernate
List<Book> books = (List<Book>)sess.createCriteria(Book.class).add( Restrictions.eq("author.information.firstName", "Marc") ).list();
We recommend using hibernate criterias for convenience and possibilities.
Regards,