I am using Java driver for mongo-db and trying to add multiple query criteria using BasicDBObjectBuilder. I have a text field where an XML is stored as String so we are using regex to form the query.
Below is my query and the output I am getting:
regexQuery.put("REQUEST_XML",BasicDBObjectBuilder
.start("$regex", ".*Main>[\r\n]<.?.?.?.?action>"+MainValue+".*")
.add("$regex", ".*Details>[\r\n]<.?.?.?.?action>" + DetailValue+ ".*").get());
regexQuery.put("NAME", "Video");
What I am getting as query is :
{ "REQUEST_XML" : { "$regex" : ".*Details>[\r\n]<.?.?.?.?action>Change.*"} , "NAME" : "Video"}
The first part with .start("$regex", ".Main>[\r\n]<.?.?.?.?action>"+MainValue+".") is not getting added to query.
Can you please let me know what is the issue ?
You are overwriting the key value pair. "$regex", ".*Details>[\r\n]<.?.?.?.?action>" + DetailValue+ ".*" overwrites "$regex", ".*Main>[\r\n]<.?.?.?.?action>"+MainValue+".*".
Use $or to pass both regex expression.
Something like
BasicDBObject regexQuery = new BasicDBObject();
regexQuery.put("$or", Arrays.asList(new BasicDBObject("REQUEST_XML", new BasicDBObject("$regex", ".*Main>[\r\n]<.?.?.?.?action>"+".*")),
new BasicDBObject("REQUEST_XML", new BasicDBObject("$regex", ".*Details>[\r\n]<.?.?.?.?action>"+".*"))));
regexQuery.put("NAME", "Video");
This should output query like
{ "$or" : [{ "REQUEST_XML" : { "$regex" : ".*Main>[\r\n]<.?.?.?.?action>.*" } }, { "REQUEST_XML" : { "$regex" : ".*Details>[\r\n]<.?.?.?.?action>.*" } }], "NAME" : "Video" }
Using 3.x driver
import static com.mongodb.client.model.Filters.or;
import static com.mongodb.client.model.Filters.regex;
Bson regexQuery = or(regex("REQUEST_XML", ".*Main>[\r\n]<.?.?.?.?action>"+".*"), regex("$regex", ".*Details>[\r\n]<.?.?.?.?action>"+".*"));
Related
Following is the structure of my MongoDB document userActivity.
{
"_id" : ObjectId("5e49569f93e956eeb28eb8a6"),
"userId" : "123",
"likes" : {
"videos" : [
{
"_id" : "abc",
"title" : "This video is part of test setup",
}
]
}
}
I am using Spring Data MongoOperations to manipulate MongoDB collections. And below is the code to remove a video from videos array in likes sub-document. I have tried to first filter the document as per the user's userId. And then apply filter to update function as per videoId.
public UpdateResult removeVideoLike(String videoId, String userId) {
Query queryUser = Query.query( Criteria.where("userId").is(userId) );
Query queryVideo = Query.query( Criteria.where("id").is(videoId) );
Update update = new Update().pull("likes.videos", queryVideo );
return mongoOperations.updateFirst( queryUser , update, UserActivity.class );
}
This runs without errors but the entry is not removed. The UpdateResult has following values
matchedCount = 1
modifiedCount = 0
upsertedId = null
I am confused if it is able to match the entry in the array, why it is not removing it? What I am missing?
I have a mongo collection with objects like these:
[
{
"_id" : "a2d",
"entityType" : "Location",
"type" : "STRING",
},
{
"_id" : "a1_order",
"entityType" : "Order",
"type" : "STRING",
}
]
Trying to append the _entityType to all document's id where it is not present at the end id the id (the first object in the above case).
Using mongo with Spring, but I'm already stuck with the first step, to get all the objects with no entityType in id.
Thinking about something like this, with regex, but I'm not sure how should it look like:
Query query = new Query();
query.addCriteria( Criteria.where( "id" ).regex( "here i need the entity type of the current document" ) );
You can build your regex by '^' ('starts with' Regex).
So you need a function who point in all documents and check this filter
List<Document> result = new ArrayList<Document>();
StringBuilder idPrefix = new StringBuilder();
idPrefix.append("^");
idPrefix.append(idCode);
idPrefix.append("_");
List<Bson> filters = new ArrayList<Bson>();
filters.add(Filters.regex("_id", keyPrefix.toString()));
for (Document d : yourCollections.find(Filters.and(filters)))
list.add(d);
You actually want a "reverse regex" here, as you need to use the data in the document in order to match on another field.
Presently you can really only do this with MongoDB using $where, which evaluates JavaScript on the server. So for spring mongo, you need the BasicQuery instead, so we can construct from BasicDBObject and Code primatives:
BasicDBObject basicDBObject = new BasicDBObject("$where",
new Code("!RegExp('_' + this.entityType + '$','i').test(this.id)"));
BasicQuery query = new BasicQuery(basicDBObject);
That will test the "id" field in the document to see if it matches the value from entityType at the "end of the string" and without considering "case". The ! is a Not condition, so the "reverse" of the logic is applied to "not match" where the field actually did end that way.
From system.profile collection I have documents like this:
{
"op" : "command",
"ns" : "..",
"command" : {
"count" : "..",
"query" : {
"$and" : [
...
]
}
},
"responseLength" : 48,
"millis" : 18,
}
Some queries don't have the command field instead they have 'query' field. I want to check if 'command' field exist. If it does then append that to my Stringbuilder object, if not append 'query'.
UPDATE:
I have tried to use Projection as suggested by Davide by but still I am not finding a way to checking if query exist, if it does then append that.
DBCollection collection = mongoTemplate.getCollection("system.profile");
DBObject query = new BasicDBObject("command", new BasicDBObject("$exists",true));
BasicDBObject fields = new BasicDBObject("command",1).append("millis", 1).append("ts", 1);
DBCursor cursor = collection.find(query, fields);
while(cursor.hasNext()) {
sb.append(cursor.next());
sb.append(System.getProperty("line.separator"));
}
return sb;
}
You need to use the following method:
public DBCursor find(DBObject query, DBObject projection);
From java doc:
projection - specifies which fields MongoDB will return from the documents in the result set.
Following is my Java controller method code
public List<MyClass> getStudentList(String studentName){
studentName = ".*" + studentName + ".*";
/* BasicDBObject field = new BasicDBObject();
field.put("regNo", 1);
field.put("name", 1);
field.put("collName", 1);
field.put("deptName", 1); */
Query query = new Query(Criteria.where("name").regex(studentName, "i"));
return mongoTemplate.find(query,MyClass.class, COLLECTION_NAME);
}
My Db looks like this
"regNo" : "1234", "name" : "ABCD", "collName" : "UNIVERSITY COLLEGE", "deptName" : "B.E. Computer Science and Engineering", "result" : [ { "subjCode" : "CS2251", "grade" : "E", "result" : "PASS", "subjName" : "Design and Analysis of Algorithms" }]
I want to select only regNo, name, collName and deptName. How can I do this?
Add this statement to query:
query.fields().include("regNo").include("name").include("collName").include("deptName").exclude("_id");
APPEND
If your codes like:
public List<MyClass> getStudentList(String studentName){
studentName = ".*" + studentName + ".*";
/* BasicDBObject field = new BasicDBObject();
field.put("regNo", 1);
field.put("name", 1);
field.put("collName", 1);
field.put("deptName", 1); */
Query query = new Query(Criteria.where("name").regex(studentName, "i"));
query.fields().include("regNo").include("name").include("collName").include("deptName").exclude("_id");
return mongoTemplate.find(query,MyClass.class, COLLECTION_NAME);
}
It should be fine.
By the query string you provided as:
var q = {
Query : {
"name" : {
"$regex" : ".*valueSearched.*",
"$options" : "i"
}
},
Fields : {
"collName" : 1,
"results" : 0, // disallowed
"_id" : 0,
"de‚Äå‚ÄãptName" : 1,
"name" : 1,
"regNo" : 1
}
};
You actually perform something similar to
query.fields().include("collName").exclude("results").exclude("_id").include("de‚Äå‚ÄãptName").include("name").include("regNo");
instead.
Please check your code accordingly. Maybe you've called query.fields().exculude("results") somewhere; ELSE, it has a bug from some part. :)
The regulation for including and excluding fields are:
If you include some fields, then only return these fields and
"_id" will return implicitly;
only "_id" is allowed to exclude;
If you exclude some normal fields, other fields will returned and
can not include other fields;
See here,it is deprecated but help you to understand
public DBCursor find(DBObject query,
DBObject fields,
int numToSkip,
int batchSize,
int options)
http://api.mongodb.org/java/current/com/mongodb/DBCollection.html#find%28com.mongodb.DBObject,%20com.mongodb.DBObject,%20int,%20int%29
If you dont want any warning ,you may use DBCursor Object.
public DBCursor(DBCollection collection,
DBObject q,
DBObject k,
ReadPreference preference)
Initializes a new database cursor
Parameters:
collection - collection to use
q - query to perform
k - keys to return from the query
preference - the Read Preference for this query
I don't use java driver but it shouldn't be much difficult.
For this issue you have to use #JsonInclude(value=Include.NON_NULL) in your pojo class like this:
#JsonInclude(value=Include.NON_NULL)
String id;
I have some documents in my mongodb as follows
{"Filename":"PHP Book.pdf","Author":"John" ,"Description":"This is my PHP Book"}
{"Filename":"Java Book.html" ,"Author":"Paul" ,"Description":"This is my JAVA Book"}
{"Filename":".NET Book.doc" ,"Author":"James" ,"Description":"This is my .NET Book"}
I have created text index on Description field and below is my code which does full text search on Description field.
m = new Mongo("10.0.0.26", 27017);
DB db = m.getDB("soft") ;
DBCollection col = db.getCollection("pocnew") ;
String collection = col.toString();
DBObject searchCmd = new BasicDBObject();
searchCmd.put("text", collection);
searchCmd.put("search", "php");
CommandResult commandResult = db.command(searchCmd);
System.out.println(commandResult);
I am getting following result
{ "serverUsed" : "/10.0.0.26:27017" , "queryDebugString" : "php||||||" , "language" : "english" , "results" : [ { "score" : 0.5833333333333334 , "obj" : { "_id" : { "$oid" : "51cd7d302d45471420c1132b","Filename":"PHP Book.pdf","Author":"John" ,"Description":"This is my PHP Book"}]}}
My requirement is to display only filename field value i.e only PHP Book.pdf
please suggest me
Thanks
You may have to dig through the returned document to get to Filename
CommandResult commandResult = db.command(searchCmd);
BasicDBList results = (BasicDBList)commandResult.get("results");
for( Iterator< Object > it = results.iterator(); it.hasNext(); )
{
BasicDBObject result = (BasicDBObject) it.next();
BasicDBObject dbo = (BasicDBObject) result.get("obj");
System.out.println(dbo.getString("Filename"));
}
In addition, if you just need the Filename field, you may want to add project option in searchCmd to limit the number of fields returned in search results. See the following link for text command returned document details and project option.
http://docs.mongodb.org/manual/reference/command/text/