Spring mongodb get ID of inserted item after Save - mongodb

I am working with Spring MongoDb.
I create various entities using insert method:
http://docs.spring.io/spring-data/mongodb/docs/current/api/org/springframework/data/mongodb/core/MongoOperations.html#insert-java.lang.Object-
However, all methods return void. I need to return the ObjectId of the inserted document.
What is the best way to get it?

This is pretty interesting and thought I would share. I just figured out the solution for this with the help of BatScream comment above:
You would create an object and insert it into your MongoDB:
Animal animal = new Animal();
animal.setName(name);
animal.setCat(cat);
mongoTemplate.insert(animal);
Your animal class looks like this with getters and settings for all fields:
public class Animal {
#Id
#JsonProperty
private String id;
#JsonProperty
private String name;
#JsonProperty
private String cat;
public String getId() {
return id;
}
}
AFTER you have done the insert under mongoTemplate.insert(animal);, you can actually call the method animal.getId() and it will return back the ObjectId that was created.

I had the same problem with #AlanH that animal.getId() is null. And then I just realized my id field had been set as a final field with a wither method. So of course getId() is null since the id field is immutable and the wither method returns a new object with id.
if this is the case: use animal = template.insert(animal).

Related

Using the ID value object of an aggregate for persistance with MongoDB

A classic DDD rule is that aggregates should reference each other via their ID, and that the ID of an aggregate should be a value object. So something like this (in Java):
class MyAggregate {
private MyAggregateId id;
private String someOtherField;
...
}
class MyAggregateId {
private UUID id;
}
How can i make MongoDB use MyAggregateId instead of the autogenerated ObjectID? Is that possible?
Bonus points if the answer involves doing this with spring-boot, where i hoped i could just declare public interface MyAggregateRepository extends MongoRepository<MyAggregate, MyAggregateId> {} but that does not seem to work.

How to get last record in spring mongo?

I have a transaction class which stores the each transaction of a customer,Following are the fields in this class.
class Transaction{
#Id
private String id;
private Date date;
private String customerId;
private double openBalance;
private double transctionAmount;
private double finalAmount;
}
I need to fetch only the last inserted record of a customer (let say for customerId = cust123).
I defined following function in repository.
public interface TranscationRepository extends MongoRepository<Transaction, String> {
Optional<Transaction> findTopByCustomerIdOrderByIdDesc(String id);
}
This method giving last entry not by customerId but overall. I tried few modifications to it but did not get success.
I know I can findAllByCustomer but I don't want to pull huge list of transaction which is of no use in this use case. What is correct signature in spring mongo to get last inserted record by a field? I am ok to use custom #Query also.
Thank you.

How can I store a Java HashMap<String,Double> in mongodb using Morphia?

I have a user defined class CostMatrix this class contains two properties and data type for both properties is HashMap. I am using Morphia to communicate with mongodb so my entity class looks like this
#Entity(value = "CostMatrix",noClassnameStored = false)
public class CostMatrix {
#Id
private String id;
private HashMap<String,Double> distances;
private HashMap<String,Double> durations;
public CostMatrix(){}
public CostMatrix(String id, HashMap<String,Double>distances, HashMap<String,Double>durations) {
this.id = id;
this.distances = distances;
this.durations = durations;
}
I am unable to store object properly into database object is stored any how but when I retrieve its just returns id and class name any thoughts would be appreciated.
if you don't want to have any class/package names in your collection just put the noClassnameStored flag to true.
#Entity(value = "CostMatrix",noClassnameStored =**true**)
As for the saving part, do you fill some values into your maps? The mapper will ignore null values and empty lists.

Morphia (MongoDB) Datastore "get" returns null

So I started working with Morphia and I'm encountering a weird problem.
Here's my entity class
#Entity("movies")
#Indexes(#Index(value = "Name", fields = #Field("Name")))
#Converters(LocalDateConverter.class)
public class MovieDetails implements Serializable
{
#Id
public String Id;
public String Name;
public String Description;
public String ImageName;
public LocalDate ReleaseDate;
public String Director;
public int Duration;
public String Genres;
public String Actors;
public MovieDetails()
{
}
public MovieDetails(String id, String name, String description, String imageName, String director, String actors, LocalDate releaseDate, String genres, int duration)
{
this (name, description, imageName, director, actors, releaseDate, genres, duration);
Id = id;
}
public MovieDetails(String name, String description, String imageName, String director, String actors, LocalDate releaseDate, String genres, int duration)
{
Name = name;
Description = description;
ImageName = imageName;
Director = director;
Actors = actors;
ReleaseDate = releaseDate;
Genres = genres;
Duration = duration;
}
}
Here's my little test:
final Morphia morphia = new Morphia();
// tell Morphia where to find your classes
// can be called multiple times with different packages or classes
morphia.mapPackage("nimrodpasha.cinema.objects");
// create the Datastore connecting to the default port on the local host
final Datastore datastore =
morphia.createDatastore(SingleMongoClient.getInstance().getClient(),
Constants.DB.TICKET_DATABASE);
datastore.ensureIndexes();
//region new movie
MovieDetails movie = new MovieDetails("The Mask", "Stanley Ipkiss (Jim Carrey) is a bank clerk that is an incredibly nice man. Unfortunately," +
" he is too nice for his own good and is a pushover when it comes to confrontations. After one of the worst days of his life, he finds a mask that depicts Loki, " +
"the Norse night god of mischief. Now, when he puts it on, he becomes his inner, self: a cartoon romantic wild man. However, a small time crime boss, Dorian Tyrel (Peter Greene), " +
"comes across this character dubbed The Mask by the media. After Ipkiss's alter ego indirectly kills his friend in crime," +
" Tyrel now wants this green-faced goon destroyed.",
"MASK.jpg", "Chuck Russell", "Jim Carrey as Stanley Ipkiss/The Mask,Cameron Diaz as Tina Carlyle,Amy Yasbeck as Peggy Brandt,Joely Fisher as Maggie", new LocalDate(1994, 2, 1), "Action,Comedy,CrimeAction,Family,Fantasy", 88);
//endregion
// Clearing the db first
datastore.delete(datastore.createQuery(MovieDetails.class));
// Saving a new entity and getting the result saved id
String id = (String) datastore.save(movie).getId();
// This returns as null
MovieDetails movieRetrieved = datastore.get(MovieDetails.class, id);
// This returns with one item
List<MovieDetails> allMovies = datastore.createQuery(MovieDetails.class).asList();
When I use
datastore.get(MovieDetails.class, id)
I get null
When I use:
datastore.createQuery(MovieDetails.class).asList();
I do see my movie in the DB, with the Id used in the get function.
Tried the id in many variations... toString(), ObjectId(id), Key (The value returned from the save result).
The Id in the DB (viewed with Mongo Explorer) does show as something which isn't string (blue colored), suspicious:
Mongo Explorer item picture
Any ideas?
Edit:
* the Id is indeed a string, the cast works and it was verified using watch + instanceof
Edit 2:
* Somehow the cast from ObjectId to String passed and the Id wasnt really a String.
I would change your I'd field from String to a BSON ObjectId field which MongoDB will automagically assign on save. If you then do your get call with the ObjectId as the parameter, it should work. Using ObjectId as your ID field is highly recommended with Mongo.
I am guessing that Morphia is trying to marshall an ObjectId into your String Id field and there is a small bug somewhere. I would try calling datastore.get(Example.class, new ObjectId(id)).
After Nic Cottrell (Thanks!) answer I've had a new perspective of the problem.
As my #Id field was not assigned by me it was automaticaly assigned in the DB as ObjectId.
As I still want to use String I've simply assigned the #Id field on object creation.
Id = ObjectId.get().toString();
found the solution on:
MongoDB / Morphia saves technical id as ObjectId although it's a String in Java

(JDBI/Dropwizard) PSQLException when retrieving auto-incremented id from PostgreSQL

I'm trying to set up a dropwizard project but I'm stuck. When I try to get the auto generated id field with #GetGeneratedKeys then I'm getting the following Exception:
org.postgresql.util.PSQLException: Bad value for type long : foo.
The request is a simple JSON Request
{"name":"foo"}
The INSERT into the database is successful but it seems that the statement returns the value of the name instead of the generated id. How can I solve this?
I use postgresql, and the table project contains a primary key field "id" with nextval('project_id_seq'::regclass). Here are the POJO, DAO and Resource Classes I use:
public class Project {
private long id;
private String name;
public Project() { // Jackson deserialization }
public Project(long id, String name) {
this.id = id;
this.name = name;
}
...
}
#RegisterMapper(ProjectMapper.class)
public interface ProjectDAO {
#SqlUpdate("insert into project (name) values (:name)")
#GetGeneratedKeys
public long insert(#Bind("name") String name);
}
#Path("/project")
#Consumes({MediaType.APPLICATION_JSON})
#Produces({MediaType.APPLICATION_JSON})
public class ProjectResource {
ProjectDAO projectDAO;
public ProjectResource(ProjectDAO personDAO) {
this.projectDAO = personDAO;
}
#POST
#Timed
public Response add(#Valid Project project) {
long newId = projectDAO.insert(project.getName());
project.setId(newId);
return Response.status(Response.Status.CREATED)
.entity(project).build();
}
}
===============
UPDATE
I just figured out that this relates to the fact that my id column isn't the first column in my table. The column name is. The problem occurs because #GetGeneratedKeys is using org.skife.jdbi.v2.sqlobject.FigureItOutResultSetMapper which is using org.skife.jdbi.v2.PrimitivesMapperFactory which returns org.skife.jdbi.v2.util.LongMapper.FIRST. This mapper is calling
java.sql.ResultSet.getLong(1) through the method extractByIndex(...) to retrieve the generated id, which isn't the id in my case...
I'll fix the issue by reorganizing the columns in the database, but I'd like to have a robust implementation if possible: Is there a way to specify the column name of the id column when using the #GetGeneratedKeys Annotation? (The org.skife.jdbi.v2.util.LongMapper class contains a also method called extractByName(...))
This is an issue in the jdbi implementation and is fixed in a newer version as described in https://github.com/jdbi/jdbi/issues/114