Remove [ "" : from mongoDb result using Java - java

To remove the "_id" from the mongo result I use :
DBObject allQuery = new BasicDBObject();
DBObject removeIdProjection = new BasicDBObject("_id", 0);
data.addAll(collection.find(allQuery , removeIdProjection).toArray());
The results of this query is :
{ "" : { [
{
"test1" : "test1"
{
}]}
How to remove { "" : so result is of format :
[
{
"test1" : "test1"
}
]

You are trying to put result in json object which add extra brackets here.
toArray() converts type cursor to list so you need to store it in list. You can iterate this list to access elements. You should use following code to get expected result:
DBObject allQuery = new BasicDBObject();
DBObject removeIdProjection = new BasicDBObject("_id", 0);
List cursor = collection.find(allQuery , emoveIdProjection).toArray();
System.out.println("result: " + cursor);

Related

"or" condition in embedded document java

What is the correct syntax for creating $or condition in embedded document in MongoDB Java driver?
Is it actually possible to get a cursor to embedded documents?
Suppose I have the following document:
{
statuses: [{
{
streamName: A
}{
statusA: 0
}{
statusB: 1
}
},
{
{
streamName: B
}{
statusA: 0
}{
statusB: 1
}
}]
}
I would also like to get cursor to sub documents (in array of statuses) that has at least one status bigger than 0.
This is how I did it but it didn't work:
List<BasicDBObject> obj = new ArrayList<BasicDBObject>();
DBObject query = new BasicDBObject();
obj.add(new BasicDBObject ("statuses",
new BasicDBObject ("statusA",
new BasicDBObject ("$gt",0 ) )));
obj.add(new BasicDBObject ("statuses",
new BasicDBObject ("statusB" ,
new BasicDBObject ("$gt",0 ) )));
query.put("$or",obj)
db.find(collectionName,query)
I didn't find any documentation on that.
What you have translates to
{ "$or" : [ { "statuses" : { "statusA" : { "$gt" : 0}}} , { "statuses" : { "statusB" : { "$gt" : 0}}}]}
which is used for whole document comparison.
For comparing fields inside an embedded arrays/doc you've to use dot notation.
{ "$or" : [ { "statuses.statusA" : { "$gt" : 0}} , { "statuses.statusB" : { "$gt" : 0}}]}
The equliavent java code is below
List<BasicDBObject> obj = new ArrayList<BasicDBObject>();
DBObject query = new BasicDBObject();
obj.add(new BasicDBObject ("statuses.statusA", new BasicDBObject ("$gt",0 ) ));
obj.add(new BasicDBObject ("statuses.statusB" , new BasicDBObject ("$gt",0 ) ));
query.put("$or",obj);
Alternatively you can use $elemMatch to run matches on embedded arrays. Similar to what you've but $elemMatch applies condition to each fields.
Something like
{ "statuses" : { "$elemMatch" : { "$or" : [ { "statusA" : { "$gt" : 0}} , { "statusB" : { "$gt" : 0}}]}}}
Java Code
BasicDBList obj = new BasicDBList();
obj.add(new BasicDBObject ("statusA",new BasicDBObject ("$gt",0 ) ));
obj.add(new BasicDBObject ("statusB",new BasicDBObject ("$gt",0 ) ));
DBObject query = new BasicDBObject("statuses", new BasicDBObject("$elemMatch", new BasicDBObject("$or",obj)));
Count the no of matching occurrences.
Bson count = new Document("statuses", Document.parse("{$size:{\n" +
" $filter: {\n" +
" input: \"$statuses\",\n" +
" as: \"status\",\n" +
" cond: { \"$or\" : [ {$gt:[\"$$status.statusA\", 0]} , {$gt:[\"$$status.statusB\", 0]}]}\n" +
" }\n" +
" }}"));
Bson project = new Document("$project", count);
col.aggregate(Arrays.asList(project));

query to get results from mongoDB

I have the following collections in MongoDB
"userDetails" : [
{
"user" : DBRef("users", "RAVI"),
"class1" : DBRef("classes", "1"),
"class2" : DBRef("classes", "2")
},
{
"user" : DBRef("users", "TEJA"),
"class1" : DBRef("classes", "1"),
"class2" : DBRef("classes", "2")
}]
classes
{
"_id" : "1",
"maxScore" : "50",
"subject" : DBRef("subjects", "class1")
}
{
"_id" : "2",
"maxScore" : "80",
"subject" : DBRef("subjects", "class2")
}
users{
"_id" : "RAVI",
"address" : "3-2-2222",
"lastClass" : "1"
"lastScore" : ""
}
{
"_id" : "TEJA",
"address" : "5-23",
"lastClass" : "1"
}
From java program, I want to query such that when I pass input as user name I want to fetch all the details of that user and his classes details.can anyone help me out with this?
previously i tried
BasicDBObject fields = new BasicDBObject("userDetails", 1).append("userDetails", new BasicDBObject("$elemMatch", new BasicDBObject("user.$id", "RAVI")));
BasicQuery query = new BasicQuery(new BasicDBObject(), fields);
List<UserDetails> usrDetailsList = mongoTemplate.find(query, UserDetails.class);
//Considering you have data inserted in your collection, now this following code will fetch a specific record from collection:
BasicDBObject whereQuery = new BasicDBObject();
whereQuery.put("user","RAVI"); //here you are specifying that you want all details of user-RAVI
DBCursor cursor = collection.find(whereQuery);
while(cursor.hasNext()) {
System.out.println(cursor.next());
}
I got my solution with a minor change.I removed $ symbol before id and i got my answer
BasicDBObject fields = new BasicDBObject("userDetails", 1).append("userDetails", new BasicDBObject("$elemMatch", new BasicDBObject("user.id", "RAVI")));
BasicQuery query = new BasicQuery(new BasicDBObject(), fields);
List<UserDetails> usrDetailsList = mongoTemplate.find(query, UserDetails.class);
but i got stuck in another point.I want to search my query based on subject id something like following
BasicDBObject fields = new BasicDBObject("userDetails", 1).append("userDetails", new BasicDBObject("$elemMatch", new BasicDBObject("class1.$subject.$id", "class1")));
BasicQuery query = new BasicQuery(new BasicDBObject(), fields);
List<UserDetails> usrDetailsList = mongoTemplate.find(query, UserDetails.class);

How can I compose a query such as (A || B || C) && (X || Y) in MongoDB Java Driver 3.2

Unfortunately, I cannot find an example for Mongo 3.2 java driver for query like "(A or B or C) and (D or E or F or G)"
Number of parameters inside parentheses will be variable - up to hundred.
Funny thing that I've found example for "(A && B) || (X && Y)" but it doesn't help me.
How to execute queries with both AND and OR clauses in MongoDB with Java
My code produces error:
MongoQueryException: Query failed with error code 2 and error message '$or/$and/$nor entries need to be full objects'
List<Document> docs = new ArrayList<>();
for (Integer ln: input.getLastnames()) {
docs.add(new Document("lastname",ln));
}
Document queryLN = new Document(
"$or", Arrays.asList(docs)
);
docs.clear();
for (Integer fn: input.getFirstnames()) {
docs.add(new Document("firstname",fn));
}
Document queryFN = new Document(
"$or", Arrays.asList(docs)
);
Document query = new Document(
"$and", Arrays.asList(queryFN,queryLN));
List<Document> result = collectionMain.find(query).into(new ArrayList<Document>());
You should use an "in" query in such condition when you have a long unknown list of OR conditions.
An example code:
try {
MongoClient mongo = new MongoClient();
DB db = mongo.getDB("so");
DBCollection coll = db.getCollection("employees");
List<Integer> ageList = new ArrayList<>();
ageList.add(30);
ageList.add(35);
List<String> nameList = new ArrayList<>();
nameList.add("Anna");
BasicDBObject query = new BasicDBObject("$and", Arrays.asList(
new BasicDBObject("age", new BasicDBObject("$in", ageList)),
new BasicDBObject("name", new BasicDBObject("$in", nameList)))
);
DBCursor cursor = coll.find(query);
while(cursor.hasNext()) {
System.out.println(cursor.next());
}
}catch (Exception ex){
ex.printStackTrace();
}
To experiment with the above code, you can add the following entries in your MongoDB:
db.employees.insert({"name":"Adma","dept":"Admin","languages":["german","french","english","hindi"],"age":30, "totalExp":10});
db.employees.insert({"name":"Anna","dept":"Admin","languages":["english","hindi"],"age":35, "totalExp":11});
db.employees.insert({"name":"Bob","dept":"Facilities","languages":["english","hindi"],"age":36, "totalExp":14});
db.employees.insert({"name":"Cathy","dept":"Facilities","languages":["hindi"],"age":31, "totalExp":4});
db.employees.insert({"name":"Mike","dept":"HR","languages":["english", "hindi", "spanish"],"age":26, "totalExp":3});
db.employees.insert({"name":"Jenny","dept":"HR","languages":["english", "hindi", "spanish"],"age":25, "totalExp":3});
The above code produces this query:
db.employees.find({"$and":[{"age":{"$in":[30, 35]}},{"name":{"$in":["Anna"]}}]});
And the output is:
{ "_id" : { "$oid" : "57ff3e5e3dedf0228d4862ad"} , "name" : "Anna" , "dept" : "Admin" , "languages" : [ "english" , "hindi"] , "age" : 35.0 , "totalExp" : 11.0}
A good article on this topic: https://www.mkyong.com/mongodb/java-mongodb-query-document/
Read these as well: https://stackoverflow.com/a/8219679/3896066 and https://stackoverflow.com/a/14738878/3896066
Let's first understand your code. We will make it simple by replacing the for loops with simple statements and add some print statements.
List<Document> docs = new ArrayList<>();
docs.add(new Document("lastname","Walker"));
docs.add(new Document("lastname","Harris"));
Document queryLN = new Document("$or", Arrays.asList(docs));
docs.clear();
System.out.println(queryLN.toJson());//{ "$or" : [[]] }
docs.add(new Document("firstname", "Pat"));
docs.add(new Document("firstname", "Matt"));
Document queryFN = new Document("$or", Arrays.asList(docs));
System.out.println(queryLN.toJson());//{ "$or" : [[{ "firstname" : "Pat" }, { "firstname" : "Matt" }]] }
System.out.println(queryFN.toJson());//{ "$or" : [[{ "firstname" : "Pat" }, { "firstname" : "Matt" }]] }
Document query = new Document("$and", Arrays.asList(queryFN, queryLN));
System.out.println(query.toJson());//{ "$and" : [{ "$or" : [[{ "firstname" : "Pat" }, { "firstname" : "Matt" }]] }, { "$or" : [[{ "firstname" : "Pat" }, { "firstname" : "Matt" }]] }] }
List<Document> result = collectionMain.find(query).into(new ArrayList<Document>());
Observations:
docs is already a list. Using Arrays.asList on docs, creates a list of list, which is not acceptable for the $and, $or, $nor. These operators accept a list of Documents. That explains the error message.
Arrays.asList does not create a copy of the array or the list that it receives. It just creates a wrapper over it. Also, new document() does not copy the list that it receives with "$or", just references the original list. Hence, calling docs.clear() will reset the content in $or of queryLN.
Also, the above concept explains why the 2nd and 3rd print statements give the same output.
Let us get the code working now.
List<Document> docsLN = new ArrayList<Document>();
List<Document> docsFN = new ArrayList<Document>();
for (Integer ln: input.getLastnames()) {
docsLN.add(new Document("lastname",ln));
}
Document queryLN = new Document("$or", docsLN);
for (Integer fn: input.getFirstnames()) {
docsFN.add(new Document("firstname",fn));
}
Document queryFN = new Document("$or", docsFN);
System.out.println(queryLN.toJson());
System.out.println(queryFN.toJson());
Document query = new Document("$and", Arrays.asList(queryFN, queryLN));
System.out.println(query.toJson());
List<Document> result = collectionMain.find(query).into(new ArrayList<Document>());
Also, consider replacing the $or with $in.
From the docs:
When using $or with that are equality checks for the
value of the same field, use the $in operator instead of the $or
operator.

How to get and update nested document in mongo db using java

I have a documents in mongo db as follows. I want to get and update the document having policyMap equals CostCalculation.In this CostCalculation has array format update in array elements such as 'policyName' have 'CostCalculationPolicyuserDefine' and set 'policyDes' = 'New Value' Please suggest the java code to solve this.
I searched mongo operartors but couldn't get it.
Sample mongo db document structure.
{
"policyMap" : {
"CostCalculation" : [{
"policyName" : "CostCalculationPolicyuserDefine",
"policyDesc" : "Priority user Defined Policy",
"userDefined" : 1
},
{
"policyName" : "CostCalculationPolicyuserDefine1",
"policyDesc" : "Priority user Defined Policy",
"userDefined" : 1
}]
},
"bsVer" : 2,
"bsFlag" : true,
"crBy" : "xxxxx",
"crDate" : NumberLong("1440138385345"),
"entNm" : "xxxx"
}
{
"policyMap" : {
"CostValue" : [{
"policyName" : "CostValuePolicyuserDefine",
"policyDesc" : "Priority user Defined Policy",
"userDefined" : 1
},
{
"policyName" : "CostCalculationPolicyuserDefine1",
"policyDesc" : "Priority user Defined Policy",
"userDefined" : 1
}]
},
"bsVer" : 2,
"bsFlag" : true,
"crBy" : "xxxxx",
"crDate" : NumberLong("1440138385345"),
"entNm" : "xxxx"
}
My sample java code
DBCollection coll = db.getCollection("nestedtest");
BasicDBObject searchDocument = new BasicDBObject();
searchDocument.put( "policyMap ", new BasicDBObject("$exists", new BasicDBObject("$eq", "CostCalculation")));
coll.remove(searchDocument);
What would be the similar java code to get the correct result.
Thanks.
This code works using Mongo 3 java drivers. It removes the need for all the BasicDBObjects that are in your code:
MongoClientURI uri = new MongoClientURI("mongodb://localhost:27017");
MongoClient client = new MongoClient(uri);
initialiseCollection(client);
Bson filter = Filters.exists("policyMap.costCalculation");
client.getDatabase("test").getCollection("test").deleteOne(filter);
DBCollection coll = db.getCollection("minnalPolicyMetadata");
BasicDBObject searchDocument = new BasicDBObject();
searchDocument.put("policyMap.CostCalculation",new BasicDBObject("$exists",true));
DBCursor cursor = coll.find(searchDocument);
if(cursor.count() != 0){
while(cursor.hasNext())
System.out.println(cursor.next());
}
In this way i solved this problem.Use exists operator in mongo

How to calculate unique elements in collections?

I have collection like
id : 1, url : youtube.com
also one url can be many times,
I need get whole collections and count unique elements
like
youtube 10
google 8
lycos 5
here is the code
public List<URLEntity> findAll() {
List<URLEntity> list = new ArrayList<URLEntity>();
String sort = "searchDate";
String order = "desc";
DBObject sortCriteria = new BasicDBObject(sort, "desc".equals(order) ? -1 : 1);
BasicDBObject query = new BasicDBObject();
DBCursor cursor = mongoCoreService.getDomainCollection().find(query).sort(sortCriteria);
try {
while (cursor.hasNext()) {
DBObject document = cursor.next();
URLEntity entity = new URLEntity();
entity = Converter.toObject(URLEntity.class, document);
list.add(entity);
}
} finally {
cursor.close();
}
return list;
}
thanks
You can achieve this by using the aggregate framework from MongoDB.
db.yourcollection.aggregate({ $group: { _id: '$url', total: {$sum: 1} }})
You'll obtain something like this, that you can manipulate in JAVA:
{
"result" : [
{
"_id" : "youtube.com",
"total" : 10
},
{
"_id" : "google.com",
"total" : 8
},
{
"_id" : "lycos",
"total" : 5
}
],
"ok" : 1
}
Today I found and test answer in java, here is a code
DBCollection mycoll= db.getCollection("domain");
DBObject fields = new BasicDBObject("domain", 1);
DBObject project = new BasicDBObject("$project", fields );
// Now the $group operation
DBObject groupFields = new BasicDBObject( "_id", "$domain");
groupFields.put("total", new BasicDBObject( "$sum", 1));
DBObject group = new BasicDBObject("$group", groupFields);
// run aggregation
AggregationOutput output = mycoll.aggregate(project, group);
System.out.println(output.getCommand().toString());
for (DBObject dbObject : output.results()) {
System.out.println(dbObject);
}

Categories