How do I execute a MongoDB js script using the Java MongoDriver - java

I have implemented a JavaScript function inside the Mongodb server using this example.
It works fine when I use mongo shell, but I want to run it from inside a Java program. This is the code:
public String runFunction() {
CommandResult commandResult1 = db.command("db.loadServerScripts()");
CommandResult commandResult2 = db.command("echoFunction(3)");
return commandResult2.toString();
}
I don't understand the result.

The previous answers does not work in MongoDB 3.4+. Th proper way to do this in version 3.4 and above is to create a BasicDBObject and use it as the parameter of Database.runCommand(). Here's an example.
final BasicDBObject command = new BasicDBObject();
command.put("eval", String.format("function() { %s return;}}, {entity_id : 1, value : 1, type : 1}).forEach(someFun); }", code));
Document result = database.runCommand(command);

Since MongoDB 4.2 the eval command is removed (it was deprecated in 3.0).
There is no more way to eval JavaScript scripts into MongoDB from the Java Driver.
See https://docs.mongodb.com/manual/reference/method/db.eval/

You should use DB.eval(), see the api docs and make sure that you don't do string concatenation. Pass the variables through instead.
I think your answer is probably the same answer as this other one on StackOverflow.

#Autowired
private MongoOperations mongoOperations;
private final BasicDBObject basicDBObject = new BasicDBObject();
#PostConstruct
private void initialize() {
basicDBObject.put("eval", "function() { return db.loadServerScripts(); }");
mongoOperations.executeCommand(basicDBObject);
}
private void execute() {
basicDBObject.put("eval", "function() { return echoFunction(3); }");
CommandResult result = mongoOperations.executeCommand(basicDBObject);
}
And then you can use something like:
ObjectMapper mapper = new ObjectMapper();
And MongoOperation's:
mongoOperations.getConverter().read(CLASS, DBOBJECT);
Just try to have some workaround depends on your requirements

Related

Does spring-data-mongodb supports Atlas search? need an example of it

I am trying to find how to use mongo Atlas search indexes, from java application, which is using spring-data-mongodb to query the data, can anyone share an example for it
what i found was as code as below, but that is used for MongoDB Text search, though it is working, but not sure whether it is using Atlas search defined index.
TextQuery textQuery = TextQuery.queryText(new TextCriteria().matchingAny(text)).sortByScore();
textQuery.fields().include("cast").include("title").include("id");
List<Movies> movies = mongoOperations
.find(textQuery, Movies.class);
I want smaple java code using spring-data-mongodb for below query:
[
{
$search: {
index: 'cast-fullplot',
text: {
query: 'sandeep',
path: {
'wildcard': '*'
}
}
}
}
]
It will be helpful if anyone can explain how MongoDB Text Search is different from Mongo Atlas Search and correct way of using Atalas Search with the help of java spring-data-mongodb.
How to code below with spring-data-mongodb:
Arrays.asList(new Document("$search",
new Document("index", "cast-fullplot")
.append("text",
new Document("query", "sandeep")
.append("path",
new Document("wildcard", "*")))),
new Document())
Yes, spring-data-mongo supports the aggregation pipeline, which you'll use to execute your query.
You need to define a document list, with the steps defined in your query, in the correct order. Atlas Search must be the first step in the pipeline, as it stands. You can translate your query to the aggregation pipeline using the Mongo Atlas interface, they have an option to export the pipeline array in the language of your choosing. Then, you just need to execute the query and map the list of responses to your entity class.
You can see an example below:
public class SearchRepositoryImpl implements SearchRepositoryCustom {
private final MongoClient mongoClient;
public SearchRepositoryImpl(MongoClient mongoClient) {
this.mongoClient = mongoClient;
}
#Override
public List<SearchEntity> searchByFilter(String text) {
// You can add codec configuration in your database object. This might be needed to map
// your object to the mongodb data
MongoDatabase database = mongoClient.getDatabase("aggregation");
MongoCollection<Document> collection = database.getCollection("restaurants");
List<Document> pipeline = List.of(new Document("$search", new Document("index", "default2")
.append("text", new Document("query", "Many people").append("path", new Document("wildcard", "*")))));
List<SearchEntity> searchEntityList = new ArrayList<>();
collection.aggregate(pipeline, SearchEntity.class).forEach(searchEntityList::add);
return searchEntityList;
}
}

MarkLogic POJO Data Binding Interface: JSONMappingException when performing a POJO search

I'm working with the MarkLogic POJO Databinding Interface at the moment. I'm able to write POJOs to MarkLogic. Now I want to search those POJOs and retrieve the search results. I'm following the instructions from: https://docs.marklogic.com/guide/java/binding#id_89573 However, the search results don't seem to return the correct objects. I'm getting a JSONMappingException. Here's the code:
HashMap<String, MatchedPropertyInfo> matchedProperties = new HashMap<String, MatchedPropertyInfo>();
PropertyMatches PM = new PropertyMatches(123,"uri/prefix/location2", "uri/prefix", 1234,0,"/aKey","/aLocation",true,matchedProperties);
MatchedPropertyInfo MPI1 = new MatchedPropertyInfo("matched/property/uri1", "matched/property/key1", "matched/property/location1", true,"ValueMatch1", 12, 1*1.0/3, true);
MatchedPropertyInfo MPI2 = new MatchedPropertyInfo("matched/property/uri2", "matched/property/key2", "matched/property/location2", true,"ValueMatch2", 14, 1.0/2.0, true);
PM.getMatchedProperties().put("matched/property/prefix/location1", MPI1);
PM.getMatchedProperties().put("matched/property/prefix/location2", MPI2);
PojoRepository myClassRepo = client.newPojoRepository(PropertyMatches.class, Long.class);
myClassRepo.write(PM);
PojoQueryBuilder qb = myClassRepo.getQueryBuilder();
PojoPage<PropertyMatches> matches = myClassRepo.search(qb.value("uri", "uri/prefix/location2"),1);
if (matches.hasContent()) {
while (matches.hasNext()) {
PropertyMatches aPM = matches.next();
System.out.println(" " + aPM.getURI());
}
} else {
System.out.println(" No matches");
}
The PropertyMatches (PM) object is succesfully written to the MarkLogic database. This class contains a member: private String URI which is initiated with "uri/prefix/location2". The matches.hasContent() returns true in the example above. However, I'm getting an error on PropertyMatches aPM = matches.next();
Searching POJOs in MarkLogic and read them into your Java program requires the POJOs to have an empty constructor. In this case PropertyMatches should have public PropertyMatches(){} and MatchedPropertyInfo should have public MatchedPropertyInfo(){}
Thanks #sjoerd999 for posting the answer you found. Just to add some documentation references, this topic is discussed here: http://docs.marklogic.com/guide/java/binding#id_54408 and here: https://docs.marklogic.com/javadoc/client/com/marklogic/client/pojo/PojoRepository.html.
Also worth noting is you can have multiple parameters in the consructor, you just have to do it the Jackson way. Here are examples of two ways (with annotations and without): https://manosnikolaidis.wordpress.com/2015/08/25/jackson-without-annotations/
I'd recommend using annotations as that's built-in with Jackson. But if you want to do it without annotations, here's the code:
ObjectMapper mapper = new ObjectMapper();
// Avoid having to annotate the Person class
// Requires Java 8, pass -parameters to javac
// and jackson-module-parameter-names as a dependency
mapper.registerModule(new ParameterNamesModule());
// make private fields of Person visible to Jackson
mapper.setVisibility(FIELD, ANY);
If you want to do this with PojoRepository you'll have to use the unsupported getObjectMapper method to get the ObjectMapper and call registerModule and setVisibility on that:
ObjectMapper objectMapper = ((PojoRepositoryImpl) myClassRepo).getObjectMapper();

How to execute mongo query from spring's mongo template?

I am trying to execute queries like "db.post.find().pretty()" from executeCommand of mongoTemplete of spring framework. But I am unable to do it?Is there a way to execute queries like above directly from mongotempelate? Any help is appreciated.
Here is my code:
public CommandResult getMongoReportResult(){
CommandResult result=mongoTemplate.executeCommand("{$and:[{\"by\":\"tutorials point\"},{\"title\": \"MongoDB Overview\"}]}");
return result;
}
yes of course, but you should pass a BasicDBObject as parameter, and not a String, like this:
(and your command wasn't formatted correctly, see find command
BasicDBList andList = new BasicDBList();
andList.add(new BasicDBObject("by", "tutorials point"));
andList.add(new BasicDBObject("title", "MongoDB Overview"));
BasicDBObject and = new BasicDBObject("$and", andList);
BasicDBObject command = new BasicDBObject("find", "collectionName");
command.append("filter", and);
mongoTemplate.executeCommand(command);

Call MongoDB function from Java

I'm trying to call a stored JavaScript function from the MongoDB Java driver.
I have been following this guide to store the function on the DB server and I'm able to call the function from the mongo shell and have the result returned.
However I cannot figure out how to call the same function in Java?
According to this http://api.mongodb.org/java/current/com/mongodb/DB.html#doEval-java.lang.String-java.lang.Object...- there's a method called doEval
I have also tried to use it with this method:
public static String callFunction() {
try (MongoClient client = new MongoClient("localhost")) {
com.mongodb.DB db = client.getDB("TestDB");
return db.doEval("echoFunction", 3).toString();
}
}
But when I call the method this is what I get:
{ "retval" : { "$code" : "function (x) {\n return x;\n}"} , "ok" : 1.0}
and I would expect to get the number 3 back in this case.
Another problem with the above code is that the method client.getDB() is deprecated. As I understand it the new method to call is client.getDatabase() and it returns a MongoDatabase object, but according to the API there is no method to execute a function.
So my question is: Is it possible to execute a stored JavaScript function on the database server from Java and get back the result of that function? And if it is possible, I would appreciate some help on how to do it?
Thank you.
Edit:
According to a comment on Calling server js function on mongodb from java:
"It seems like getNextSequence is a function written in the mongo
javascript shell. Neither the database (mongod) nor the Java side
knows this function exists and neither is able to interprete the
Javascript code the function contains. You will have to reimplement it
in Java. "
The function I'm trying to implement is a bit more complex than the example above - it's supposed to return a collection of documents and that does not seems to be working using the db.doEval method.
So I guess the comment is correct?
You can do all this with java driver.
MongoClient mongoClient = new MongoClient();
MongoDatabase mdb = mongoClient.getDatabase("TestDB");
/* run this <code snippet> in bootstrap */
BsonDocument echoFunction = new BsonDocument("value",
new BsonJavaScript("function(x1) { return x1; }"));
BsonDocument myAddFunction = new BsonDocument("value",
new BsonJavaScript("function (x, y){ return x + y; }"));
mdb.getCollection("system.js").updateOne(
new Document("_id", "echoFunction"),
new Document("$set", echoFunction),
new UpdateOptions().upsert(true));
mdb.getCollection("system.js").updateOne(
new Document("_id", "myAddFunction"),
new Document("$set", myAddFunction),
new UpdateOptions().upsert(true));
mdb.runCommand(new Document("$eval", "db.loadServerScripts()"));
/* end </code snippet> */
Document doc1 = mdb.runCommand(new Document("$eval", "echoFunction(5)"));
System.out.println(doc1);
The result is also:
Document{{retval=5.0, ok=1.0}}
You should do this instead:
return db.doEval("echoFunction(3)").toString();
If you use just function name in eval you only refer to JavaScript variable on server side storing code of function. It doesn't execute it. When you use parentheses you request to actually execute a function. If you need to send something more complex than a number I would advise to use JSON serializer.
I resolved the same issue in the following way:
I run a command in mongoShell to create my stored JavaScript functions:
db.system.js.save(
{
_id: "echoFunction" ,
value : function(x1) { return x1; }
}
)
db.system.js.save(
{
_id : "myAddFunction" ,
value : function (x, y){ return x + y; }
}
);
db.system.js.save(
{
_id: "fullFillCollumns" ,
value : function () {
for (i = 0; i < 2000; i++) {
db.numbers.save({num:i}); } }
}
);
To execute this functions from MongoDB Java Driver:
MongoClient mongoClient = new MongoClient();
MongoDatabase db = mongoClient.getDatabase("databaseName");
db.runCommand(new Document("$eval", "fullFillCollumns()"));
Document doc1 = db.runCommand(new Document("$eval", "echoFunction(5)"));
System.out.println(doc1);
Document doc2 = db.runCommand(new Document("$eval", "myAddFunction(5,8)"));
System.out.println(doc2);
I see that the collection numbers were created and filled with values. In the IntellijIdea console I see:
Document{{retval=5.0, ok=1.0}}
Document{{retval=13.0, ok=1.0}}

How to query mongodb with “like” using the java api?

this question is very similar to another post
I basically want to use the mongodb version of the sql "like" '%m%' operator
but in my situation i'm using the java api for mongodb, while the other post is using mongodb shell
i tried what was posted in the other thread and it worked fine
db.users.find({"name": /m/})
but in java, i'm using the put method on the BasicDBObject and passing it into the find() method on a DBCollections object
BasicDBObject q = new BasicDBOBject();
q.put("name", "/"+m+"/");
dbc.find(q);
but this doesn't seem to be working.
anyone has any ideas?
You need to pass an instance of a Java RegEx (java.util.regex.Pattern):
BasicDBObject q = new BasicDBObject();
q.put("name", java.util.regex.Pattern.compile(m));
dbc.find(q);
This will be converted to a MongoDB regex when sent to the server, as well as any RegEx flags.
You must first quote your text and then use the compile to get a regex expression:
q.put("name", Pattern.compile(Pattern.quote(m)));
Without using java.util.Pattern.quote() some characters are not escaped.
e.g. using ? as the m parameter will throw an exception.
To make it case insensitive:
Document doc = new Document("name", Pattern.compile(keyword, Pattern.CASE_INSENSITIVE));
collection.find(doc);
In spring data mongodb, this can be done as:
Query query = new Query();
query.limit(10);
query.addCriteria(Criteria.where("tagName").regex(tagName));
mongoOperation.find(query, Tags.class);
Document doc = new Document("name", Pattern.compile(keyword));
collection.find(doc);
Might not be the actual answer, ( Executing the terminal query directly )
public void displayDetails() {
try {
// DB db = roleDao.returnDB();
MongoClient mongoClient = new MongoClient("localhost", 5000);
DB db = mongoClient.getDB("test");
db.eval("db.test.update({'id':{'$not':{'$in':[/su/]}}},{$set:{'test':'test3'}},true,true)", new Object[] {});
System.out.println("inserted ");
} catch (Exception e) {
System.out.println(e);
}
}
if(searchType.equals("employeeId"))
{
query.addCriteria(Criteria.where(searchType).regex(java.util.regex.Pattern.compile(searchValue)));
employees = mongoOperations.find(query, Employee.class, "OfficialInformation");
}

Categories

Resources