Do I have to have a domain object to query mongodb?
What if I just want some raw data to be displayed? What would be the syntax to query mongodb from my controller?
I tried
"def var = db.nameOfMyCollection.find()"
but it says no such property as db in my controller class.
I know that my application is connecting to the database because I am monitoring mongo server log and it increases the number of connections by one when I launch my grails app.
Assuming you have added mongodb java driver dependency in build config and refreshed your dependencies.
Create a grails service named MongoService.groovy and put the following code.
Dont forget to import mongodb
package com.organisation.project
import com.mongodb.*
class MongoService {
private static MongoClient mongoClient
private static host = "localhost" //your host name
private static port = 27017 //your port no.
private static databaseName = "your-mongo-db-name"
public static MongoClient client() {
if(mongoClient == null){
return new MongoClient(host,port)
}else {
return mongoClient
}
}
public DBCollection collection(collectionName) {
DB db = client().getDB(databaseName)
return db.getCollection(collectionName)
}
}
We can now use this MongoService in our controllers or other services.
Now you can do following stuff in your controller.
Dont forget to import mongodb.DBCursor
package com.organisation.project
import com.mongodb.DBCursor
class YourControllerOrService {
def mongoService //including Mongo service
def method(){
def collection = mongoService.collection("your-collection-name")
DBCursor cursor = collection.find()
try{
while(cursor.hasNext()){
def doc = cursor.next()
println doc //will print raw data if its in your database for that collection
}
}finally {
cursor.close()
}
}
}
For more info Refer mongodb java docs
Ok, solved.
This is how you go about accessing the database.
import com.mongodb.*
MongoClient mongoClient = new MongoClient("localhost", 27017)
DB db = mongoClient.getDB("db");
I actually solved it using Java and then pasted it into groovy and it works there as well which shouldn't come as a surprise. The difference is that in Java you actually have to import the jar driver, but in Grails, you install the Mongo GORM plugin.
Assuming you are using the MongoDB GORM Plugin, if you have domain classes in your grails application, you can use them as you would with any relational db backend.
However, per this documentation, you can access the low-level Mongo API in any controller or service by first declaring a property mongo, just as you would a service, then getting the database you are targeting:
def mongo
def myAction = {
def db = mongo.getDB("mongo")
db.languages.insert([name: 'Groovy'])
}
Related
Im currently working with Dependency injection in my services and im curious what are the best practices in mongoDB.
My class use IMongoDatabase which is DI in constructor, but VS warns me that "This interface is not quaranteed to remain stable. Implementors should use MongoDatabaseBase.
I have seen both Client and Collection being passed in constructor in various examples.
At the moment i create Client, GetDatabase and then register it as a singleton for my other services to use.
I am using .Net 6.0
Nugets
MongoDB.Driver(2.15.1)
Microsoft.Extensions.Hosting
Main:
string connectionString = "mongodb://localhost:27017/"
string databaseName = "DBName"
MongoClient client = new MongoClient(connectionString);
IMongoDatabase mongoDb = client.GetDatabase(databaseName);
services.AddSingleton<IMongoDatabase>(mongoDb);
Host.CreateDefaultBuilder()
.ConfigureServices((context, services) =>
{
services.AddSingleton<IMongoDatabase>(mongoDb);
services.AddHostedService<MyServiceUsingMongo>();
})
.Build()
.Run();
Class:
private IMongoDatabase _db;
public MyServiceUsingMongo(IMongoDatabase db)
{
_db = db;
}
Thanx for any tips.
In spring boot if we want to connect to mongodb, we can create a configuration file for mongodb or writing datasource in application.properties
I am following the second way
For me, I am gettint this error
"Timeout while receiving message; nested exception is com.mongodb.MongoSocketReadTimeoutException: Timeout while receiving message
.
spring.data.mongodb.uri = mongodb://mongodb0.example.com:27017/admin
I am gettint this error If I am not using my app for 6/7 hours and after that If I try to hit any controller to retrieve data from Mongodb. After 1/2 try I am able to get
Question - Is it the normal behavior of mongodb?
So, in my case it is closing the socket after some particular hours
I read some blogs where it was written you can give socket-keep-alive, so the connection pool will not close
In spring boot mongodb connection, we can pass options in uri like
spring.data.mongodb.uri = mongodb://mongodb0.example.com:27017/admin/?replicaSet=test&connectTimeoutMS=300000
So, I want to give socket-keep-alive options for spring.data.mongodb.uri like replicaset here.
I searched the official site, but can't able to find any
You can achieve this by providing a MongoClientOptions bean. Spring Data's MongoAutoConfiguration will pick this MongoClientOptions bean up and use it further on:
#Bean
public MongoClientOptions mongoClientOptions() {
return MongoClientOptions.builder()
.socketKeepAlive(true)
.build();
}
Also note that the socket-keep-alive option is deprecated (and defaulted to true) since mongo-driver version 3.5 (used by spring-data since version 2.0.0 of spring-data-mongodb)
You can achieve to pass this option using MongoClientOptionsFactoryBean.
public MongoClientOptions mongoClientOptions() {
try {
final MongoClientOptionsFactoryBean bean = new MongoClientOptionsFactoryBean();
bean.setSocketKeepAlive(true);
bean.afterPropertiesSet();
return bean.getObject();
} catch (final Exception e) {
throw new BeanCreationException(e.getMessage(), e);
}
}
Here an example of this configuration by extending AbstractMongoConfiguration:
#Configuration
public class DataportalApplicationConfig extends AbstractMongoConfiguration {
//#Value: inject property values into components
#Value("${spring.data.mongodb.uri}")
private String uri;
#Value("${spring.data.mongodb.database}")
private String database;
/**
* Configure the MongoClient with the uri
*
* #return MongoClient.class
*/
#Override
public MongoClient mongoClient() {
return new MongoClient(new MongoClientURI(uri,mongoClientOptions().builder()));
}
I have passed a parameter from a JSP to servlet. How do I include this in the find() query to search for that result in MongoDB?
Assuming that you have resolved all JSP/servlet stuff, take a look to this tutorial about Java Mongo Driver where you can find how to do that and other basics things.
Following this tutorial you can define filters in your query as follows:
package com.mongoclient.MongoHelloWorld;
import com.mongodb.MongoClient;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import org.bson.Document;
import static com.mongodb.client.model.Filters.eq;
public class MongoHelloWorldApplication {
public static void main(String[] args) {
// Create Mongo connection to the DB
MongoClient mongoClient = new MongoClient( "localhost", 27017);
// Select the DB
MongoDatabase database = mongoClient.getDatabase("myDatabase");
// Select the collection
MongoCollection<Document> collection = database.getCollection("myCollection");
// Make the query
Document myDoc = collection.find(eq("myField", "myValue")).first();
// Print result
System.out.println(myDoc.toJson());
}
}
In the previous example I use eq for equality comparison but you have java class like gt or lt for inequality comparison, and, or and so on... You could check the doc for more examples.
Regards!
My journey begins with me trying to configure Java driver of MongoDB to use UUID v4 instead of Legacy UUID v3 which is set by default.
I've found this solution here https://groups.google.com/forum/#!msg/mongodb-user/ZJKQpMpCMU4/dW5ATHTcAvgJ which works.
But as he states:
Note that when using the legacy API the codec registry is ignored, so
this will not use the overridden UUIDCodec
it doesn't work with my MongoRepositoy.
This is my actual configuration:
#Bean
public MongoDbFactory mongoDbFactory() throws Exception {
ServerAddress server = new ServerAddress(host,port);
MongoClientOptions.Builder mcoBuilder = MongoClientOptions.builder();
CodecRegistry codecRegistry = fromRegistries(fromCodecs(new UuidCodec(UuidRepresentation.STANDARD)),
MongoClient.getDefaultCodecRegistry());
mcoBuilder.codecRegistry(codecRegistry).build();
MongoClientOptions options = mcoBuilder.build();
MongoClient mongoClient = new MongoClient(server,options);
return new SimpleMongoDbFactory(mongoClient, mongoDataBase);
}
#Bean
public MongoTemplate mongoTemplate() throws Exception {
MongoTemplate mongoTemplate = new MongoTemplate(mongoDbFactory());
return mongoTemplate;
}
If I do:
mongoClient.getDatabase(mongoDataBase).getCollection("test")
.insertOne(new Document("_id",UUID.randomUUID()));
I get:
{ "_id" : BinData(4,"f0u8ig4TS6KaJGK93xmvNw==") }
Otherwise:
mongoTemplate.getCollection("test")
.insert(new BasicDBObject("_id", UUID.randomUUID()));
result on:
{ "_id" : BinData(3,"mUX4PTPBJo6bIjPufHf0vg==") }
I know MongoRepository uses MongoTemplate, although I've set the instance to use MongoClient and not the old Mongo, still not working. Is there any solution?
MongoClient extends Mongo, which has reference to legacy api DB class via getDB(). Although you've registered the new UUID codec with MongoClient which can only be used when you use getDatabase() to get MongoDatabase which spring mongo template current version doesn't and uses getDB(). So your changes to registry are never used.
Spring MongoDB 2.0.0 versions has been updated to use new java driver api. So your changes should work as expected against 2.0.0 version.
http://docs.spring.io/spring-data/data-mongo/docs/2.0.0.M4/reference/html/
I'm trying to put some of my domain classes into the MongoDB using the mongoDB grails plugin. Some of the classes stays in MySQL. Everything works fine even the saving of domain class instances into the MongoDB (for example in service on controller code). However, If I try to save the instance from the afterUpdate() of certain not-mongoDB class it doesn't work. It doesn't throw any exception or whatever...
My not-mongoDB domain class:
class CarState extends AbstractCarState {
...
def afterUpdate() {
def logItemInstance = new CarStateLogItem(this.properties)
logItemInstance.save(failOnError: true)
}
}
MongoDB domain class:
class CarStateLogItem extends AbstractCarState {
ObjectId id
static mapWith = "mongo"
...
}
The weird thing is that if I run the afterUpdate() code from controller it saves into the MongoDB. Am I something missing? Or why I cannot save the instance?
Thanks for any advice,
Mateo
I think you need to initiate a new transaction in order to save in mongodb. If you notice, the transaction for CarState will be of MySQL. In order to transact with mongodb from the afterUpdate event there has to be a new mongodb transaction. Try this.
def afterUpdate() {
CarStateLogItem.withTransaction{status ->
def logItemInstance = new CarStateLogItem(this.properties)
logItemInstance.save(failOnError: true)
}
}