spring-data-mongo, how to return _id back for saved objects from mongo? - mongodb

I am newbie to the Spring Data mongo. I have documents which has same FirstName say John, but MiddleName and LastName are different.
Also from UI, some students populating data (feeding data via forms) which has also FirstName say John and again MiddleName and LastName would be different.
Now, when I am saving User Object (which has FirstName, MiddleName, LastName, Age, Sex etc..etc..) into mongo using MongoTemplate. I need to return back "_id" (which mongo create by default if we don't provide it explicitly) of those each saved User object.
Could you please provide any example / guidance? Please help.

If you are saving with mongo template your object Id will be set after insertion (as Oliver Gierke has writen) of the object so you can do it like this.
//User object annotated with #Document
User user = new User(String name);
user.setWhatever(something);
mongoTemplate.save(user);
//now the user object should be populated with generated id;
return user.getId();
but you can use normal CrudRepository and use it with
<mongo:repositories base-package="your.package" />

Spring Data MongoDB will automatically populate the identifier property of your domain object with the generated identifier value.
#Document
class User {
ObjectId id; // by convention, use #Id if you want to use a different name
String firstname, lastname;
…
}
If an object of this class is persisted with the id property set to null, the object will have the property set after it has been persisted via MongoTempalte.
All of this is also described in the reference documentation.

Related

MongoDB keeps generating a new id even after setting the id property when saving in the DB

In my application I generated ids using another database and I need to use this already created ids in mongo aswell. Setting the id before saving the object just returns an object with a generated id by mongo. Is there any configuration for the mongodb to not do this?
SampleObject {
private String id;
}
SampleObject sampleObject = new SampleObject();
sampleObject.setId("f9de2416-1d10-11ec-a8b5-00ff37757c54");
repository.save(sampleObject); // returns the object saved but with a different id (generated by mongo not what we set)
Could you retry with the Annotation of #Id. Based on the document you need to annotate #Id to map to _id.
#Document
public class SampleObject {
#Id
private ObjectId id;
}

GORM - get raw DB value for domain class properties

I'm using GORM for MongoDB in my Grails 3 web-app to manage read/writes from DB.
I have the following 2 domain classes:
class Company {
String id
}
class Team {
String id
Company company
}
For teams, their company is saved on DB as String, and with GORM I can simply use team.company to get an instance of Company domain class.
However, I need to override the getter for company, and I need the raw value for company id (as stored on DB), without GORM getting in the way and performing its magic.
Is there a way to get the raw String value?
Any help is welcome! Thanks in advance
Update (May 27)
Investigating #TaiwaneseDavidCheng suggestion, I updated my code to
class Company {
String id
}
class Team {
String id
Company company
String companyId
static mapping = {
company attr: "company" // optional
companyId attr: "company", insertable: false, updateable: false
}
}
Please note that I'm using GORM for MongoDB, which (citing the manual) tries to be as compatible as possible with GORM for Hibernate, but requires a slightly different implementation.
However I found out (by trial&error) that GORM for MongoDB doesn't support a similar solution, as it seems only one property at a time can be mapped to a MongoDB document property.
In particular the last property in alphabetical order wins, e.g. companyId in my example.
I figured out a way to make the whole thing work, I'm posting my own answer below.
given a non-insertable non-updateable column "companyId" in domain class
class Company {
String id
}
class Team {
String id
Company company
Long companyId
static mapping = {
company column:"companyId"
companyId column:"companyId",insertable: false,updateable: false
}
}
(Follows the edit to my question above)
I defined a custom mapping, and made use of Grails transients by also defining custom getter and setter for team's company.
class Company {
String id
}
class Team {
String id
Company company
String companyId
static mapping = {
companyId attr: "company" // match against MongoDB property
}
static transients = [ 'company' ] // non-persistent property
Company getCompany() {
return Company.get(companyId)
}
void setCompany(Company company) {
companyId = company.id
}
}

myBatis select to existing object

Is it possible to run a select query that updates an existing java object with myBatis.
For example given this existing java object:
Customer{
int id;
String firstName;
String lastName;
}
lets say I already have a Customer instance C with an Id of 1.
how can I run a myBatis select query that will update that instance rather than create a new instance.
If you need to update the object in memory, you would have to setter each attribute of the object in memory with the result of the query.
Customer customer = new Customer(1,"C",null);//Object in memory
Customer customerQuery = selectQueryMyBatis(); //Query object
customer.setFirstName(customerQuery.getFirstName());
customer.setLastName(customerQuery.getLastName());

Spring Data MongoDb - Manual Reference ObjectId to String

Say I have a User class which has a manual reference to a customer document:
public class User(){
#Id
public String id;
public String name;
public String customerId;
}
I want both the id & customerId to be stored as an ObjectId in mongo.
When saving a User document, the "id" gets converted to an ObjectId, however, the customerId gets saved as a string. I could have customerId of type ObjectId, but I would rather have the POJO as a string and have the customerId automatically convert to ObjectId when saving/querying. There does not seem to be any built in annotation which behaves like #Id, but can be used for manual references. How would I go about creating one, or is there a better solution? I have read a bit above converters, but I do not want to re-map the whole POJO to a DBObject.
Any advice would be appreciated.
when you get your customer data you have to create the objectId yourself.
Db.Customer.find({"_id" : new ObjectId("$valueFromUserTable")});
so in Spring Java you would:
ObjectId objId = new ObjectId("$valueFromUserTable");
Query query = new Query(Criteria.where("_id").is(objId));
Customer customer = super.mongoOps.find(query, Customer.class);

Grails MongoDB Update object with Association

I can't seem to understand where I am going wrong currently when I attempt to update my User domain model that has a hasOne association to a Profile object.
My domain models are as follows:
class User {
static hasOne = [profile: Profile]
static fetchMode = [profile: 'eager']
ObjectId id
String username
}
class Profile {
static belongsTo = [user: User]
ObjectId id
String familyName
String givenName
}
I am able to persist a User with a profile originally but when attempting to update the User object I get validation errors.
Validation error occurred during call to save():
- Field error in object 'co.suitable.User' on field 'profile.familyName': rejected value [null]
- Field error in object 'co.suitable.User' on field 'profile.givenName': rejected value [null]
I am able to print out the user.profile ID and also the user.profile.familyName before saving the object. Like the following:
println(user.profile.familyName)
println(user.profile.id.toString())
user.save(flush: true, failOnError: true)
But I still get the validation errors before saving, i'd imagine that the println(user.profile.familyName) call is fetching the profile object if it already hasn't been loaded which I thought setting the fetchMode would have handled.
The object is able to successfully persist and save when I do:
user.profile = Profile.findById(user.profile.id)
println(user.profile.id.toString())
user.save(flush: true, failOnError: true)
I could wrap that in a service but I was hoping for a solution that would be handled by Grails if possible. Any advice or thoughts is much appreciated.
You should not apply the logic for the SQL DB to Mongo 1 to 1. Mongo and other document-oriented DBs are not originally intended to store the joins between collections. There are some workarounds, like db-refs, but they are to be used with caution.
For your case - with hasOne - I would suggest using mongo's subdocuments (mirrored as GORM's embedded objects) instead of referencing:
class User {
ObjectId id
String username
Profile profile
static embedded = [ 'profile' ]
}
class Profile {
String familyName
String givenName
}
thus you use the mongo in accordance to it's original puprose. Also querying is simpler and faster.