How to use ensureIndex with AdvancedDatastore by specifying a collection name? - mongodb

In morphia you can use #Index annotations to create automated indexes for #Entity classes. I am trying to create these indexes by specifying a collection name but couldn't find a way to do it. Using AdvancedDatastore you can save an Entity into any collection you want, but is it possible to ensure indexes on a specified collection rather than the default collection of the Entity.
advancedDatastore.ensureIndexes(Entity.class); // This will create indexes on the mapped Entities.
I am looking for a way to do the following, but I didn't see any method similar to below one, is there a workaround to achieve this:
advancedDatstore.ensureIndexes("exampleCollection", Entity.class); //create indexes of Entity.class for the exampleCollection.

Yes, you can extend the AdvancedDatastore interface and the DatastoreImpl concrete class to add ensureIndex* methods with the extra argument. We do this in our organization and it works.
There is also a pending pull request to add this feature directly to Morphia here: https://github.com/mongodb/morphia/pull/541. If you are willing to build your own Morphia jar, you can use the patch listed there.

Related

Projecting multiple fields to a POJO

Is there a way in hibernate-search 6 to project multiple fields and map them directly to a POJO object or I should handle it by myself. I'm not sure that I understand the composite method described in the documentation. For example I can do something like that:
SearchResult<List<?>> result = searchSession.search(indicies)
.select(f -> f.composite(f.field("field1"), f.field("field2"), f.field("field3"),f.field("field4")))
.where(SearchPredicateFactory::matchAll)
.fetch(20)
And then I can manually map the returned List of fields to a POJO. But is there a more fancy way to do that without the need to manually loop through the list of fields and set them to the POJO instance?
At the moment projecting to a POJO is only possible for fairly simple POJOs, with up to three fields, using the syntax shown in the documentation. For more fields than that, you have to go through a List.
If you're using the Elasticsearch backend, you can theoretically retrieve the document as a JsonObject and then use Gson to map it to a POJO.
There are plans to offer more fancy solutions, but we're not there yet.

Deciding which collection

I have an abstract class which is extended by large number of other POJOs, I need all these main POJOs to be stored in a dedicated collection.
My repository looks like this:
interface TimesliceRepository extends MongoRepository<AbstractTimeslice, String>
How can I make it so that objects are directed to the appropriate collection? Eg: AATimeslice, BBTimeslice, etc...
Or do I have to have a repository for every POJO?
Also, would read queries work? How would I be able to query for BBTimeslice only?
After some research, I came to the conclusion that for my uses cases its better to use MongoTemplate and not MongoRepository.

Changing the MongoDB collection on run time in symfony2 + doctrine

I'm using Symfony2 MongoDB + Doctrine and I want to tell doctrine to save my objects in collections with different name from the name of the class that defines the object. Also the name of the new collection should be the id of an object in different collection. For example I have a class called Posts and I want to save them in a collection named after the ID of the user in the original User collection. This means that I need to tell doctrine to save all new posts in a collection named e.g. User555 and I should be able to tell doctrine to create this collection and save there during runtime.
I can see that I can change the name of the collection statically with configuring it in the files like here: Storing a document in a different collection - Mongodb with symfony2
But I need to be able to create collections at runtime.
I will be thankful if someone points me in the right direction!
Cheers.
When you use the ORM you can do
$em->getClassMetadata('\AcmeBundle\Entity\Something')->setTableName('test')
Using the ODM you should be able to do
`$dm->getClassMetadata('\AcmeBundle\Document\Something')->setCollection('test')
I looked through the Doctrine code and it's possible. However note that by doing this you're changing the collection used for that Document for the life of the script, unless you set it back.
I don't know of any reasonable way to do this for just one entity at a time. Probably would be best to wrap the ODM by creating your own persister service.

Morphia and object graphs

I've yet to use Morphia, but I'm considering it for a current project.
Suppose I have a POJO with a number of #Reference annotations and I ask Morphia to fetch the object graph from the database. If I then make another DAO or DataStore call and ask Morphia to fetch some object that was already instantiated in the first graph, would Morphia return a reference to the already instantiated object or would it create a new instance?
If Morphia returns a new instance of the object each time, does anyone have a recommendation of how to best approach creating a Morphia-backed repository that won't duplicate already-instantiated objects?
As I see it in Morphia, it will re read every reference.
This is one of the problems, why I created Morphium. I integrated a caching layer there, so if you read a reference, this one won't be read again (at least, if you search by ID...)
We use morphia in production and there are two ways to make sure you don't load the references which is something we came across too.
One is to use the lazy loading option when you define the #Reference element in your main class. This of course means that this behavior is 'global' to that object.
The better way to do this is to not define an #Reference using Morphia and instead managing the references yourself. Let me know if you need a code sample.
I've stopped using #Reference too and instead declare something like:
ObjectId itemId
rather than having a field item. This has 2 benefits: (1) it lets me define a getter through a helper getObject(...) method which I have written with object caching and (2) it stores a simple ObjectId in the Mongo object rather than a full DBRef which includes the collection name and thus about twice the data size.

How do I use JPQL to delete entries from a join table?

I have a JPA object which has a many-to-many relationship like this:
#Entity
public class Role {
//...
#ManyToMany(fetch=FetchType.EAGER)
#JoinTable(
name="RolePrivilege",
joinColumns=
#JoinColumn(name="role", referencedColumnName="ID"),
inverseJoinColumns=
#JoinColumn(name="privilege", referencedColumnName="ID")
)
private Set<Privilege> privs;
}
There isn't a JPA object for RolePrivilege, so I'm not sure how to write a JPQL query to delete entries from the privs field of a role object. For instance, I've tried this, but it doesn't work. It complains that Role.privs is not mapped.
DELETE FROM Role.privs p WHERE p.id=:privId
I'm not sure what else to try. I could of course just write a native query which deletes from the join table RolePrivilege. But, I'm worried that doing so would interact badly with locally cached objects which wouldn't be updated by the native query.
Is it even possible to write JPQL to remove entries from a join table like this? If not I can just load all the Role objects and remove entries from the privs collection of each one and then persist each role. But it seems silly to do that if a simple JPQL query will do it all at once.
The JPQL update and delete statements need to refer to an Entity name, not a table name, so I think you're out of luck with the approach you've suggested.
Depending on your JPA provider, you could delete the entries from the JoinTable using a simple raw SQL statement (should be 100% portable) and then programmatically interact with your cache provider API to evict the data. For instance in Hibernate you can call evict() to expire all "Role.privs" collections from the 2nd level cache:
sessionFactory.evictCollection("Role.privs", roleId); //evict a particular collection of privs
sessionFactory.evictCollection("Role.privs"); //evict all privs collections
Unfortunately I don't work with the JPA APIs enough to know for sure what exactly is supported.
I also was looking for a JPQL approach to delete a many-to-many relation (contained in a joining table). Obviously, there's no concept of tables in an ORM, so we can't use DELETE operations... But I wish there were a special operator for these cases. Something like LINK and UNLINK. Maybe a future feature?
Anyway, what I've been doing to achieve this need has been to work with the collections implemented in the entity beans, the ones which map the many-to-many relations.
For example, if I got a class Student which has a many-to-many relation with Courses:
#ManyToMany
private Collection <Courses> collCourses;
I build in the entity a getter and setter for that collection. Then, for example from an EJB, I retrieve the collection using the getter, add or remove the desired Course, and finally, use the setter to assign the new collection. And it's done. It works perfectly.
However my main worry is the performance. An ORM is supposed to keep a huge cache of all objects (if I'm not mistaken), but even using it to work faster, I wonder if retrieving all and every element from a collection is really effective...
Because for me it's as much inefficient as retrieving the registries from a table and post-filter them using pure Java instead of a query language which works direct or undirectly with the internal DB engine (SQL, JPQL...).
Java is an object-oriented language and the whole point of ORM is to hide details of join tables and such from you. Consequently even contemplating deletion from a join table without considering the consequences would be strange.
No you can't do it with JPQL, that is for entities.
Retrieve the entities at either end and clear out their collections. This will remove the join tables entries. Object-oriented.