Restrict fields in Result - java

I am working with MongoDB v3.0.1 and the MongoDB Java Driver 3.0.0-RC1.
I have an user collection with fields like "username", "firstname", "lastname", "email", and so on.
Now I want to select all users but only with the fields "username", "firstname" and "lastname".
On the Mongo-Shell it is working with db.user.find({}, { "username" : true , "firstname" : true , "lastname" : true})
But how can I do it in Java? I tried it with
final BasicDBObject query = new BasicDBObject("{}", new BasicDBObject("_id", true));
final MongoCursor<Document> usersCursor = col.find(query)
For this I get an empty result back because it's translated as { "{}" : { "_id" : true , "firstname" : true , "lastname" : true}}.
I also tried it with BasicDBList, but this isn't accepted by col.find()
With the "old" Mongo 2.x driver I would use new BasicDBObject(BasicDBObject(), new BasicDBObject("username", true).append("firstname", true).append("lastname", true)
Is there a possibility to do that or do I have to fetch all fields?
Greetings
Sören

With the new CRUD API in the 3.0.0 Java driver, the proper way to do it is with the projection method that is chained off off MongoCollection.find(). Since the projection method takes an instance of the Bson interface, there are a number of different classes you can use to specify the projection:
// using BasicDBObject
collection.find().projection(new BasicDBObject("username", true)
.append("lastname", true)
.append("firstname", true))
// using the new Document class
collection.find().projection(new Document("username", true)
.append("lastname", true)
.append("firstname", true));
// Using the new Projections builder
collection.find().projection(Projections.include("username", "lastname", "firstname"));
As for the way you say it works in the 2.x driver, that's not possible, as
new BasicDBObject(BasicDBObject(), BasicDBObject("username", true)
.append("firstname", true)
.append("lastname", true)
does not compile. I'm not sure what exactly you were doing with 2.x, but the proper way to accomplish this with the DBCollection class in 2.x (which is still supported in the 3.0 driver), is:
collection.find(new BasicDBObject(), new BasicDBObject("username", true)
.append("lastname", true)
.append("firstname", true));

Have a look at the implementation of DBCollection find(). The following returns the "username", "firstname", "lastname" and "_id" fields for every document in the collection that has an "username", "firstname" and "lastname" fields:
BasicDBObject keys = new BasicDBObject();
keys.put("username", 1);
keys.put("firstname", 1);
keys.put("lastname", 1);
final MongoCursor<Document> usersCursor = col.find(new BasicDBObject(), keys);

collection
.find(new Document(...).append(...))
.projection(new Document(...).append(...))
This will give you a FindIterable and then you can iterate through as you would DBCursor.

Related

Implementing Mongodb query using $elemMatch in Java

I am using Mongo java driver to retrieve data from mongo collections. I have the following query which I am trying to implement in java:
Json is:
{
"_id" : ObjectId("56cd284767c74d3d4dd3ec80"),
"comments" : "Hello",
"statusLog" : [
{
"status" : "Submitted",
"startDate" : ISODate("2015-01-14T05:00:00.000Z"),
"endDate" : ISODate("2016-02-29T21:24:24.740Z")
},
{
"status" : "Active",
"startDate" : ISODate("2016-02-29T21:24:24.740Z")
}
],
"createdDate" : ISODate("2015-01-14T05:00:00.000Z")
}
Mongo Query:
db.CollectionName.find({},{_id: 0, createdDate:1, "statusLog": {$elemMatch: {"status":"Submitted"}}});
Here is the query in java that I have written (mongo java driver 3.4.2):
BasicDBObject query = new BasicDBObject(new BasicDBObject("statusLog",
new BasicDBObject("$elemMatch", new BasicDBObject("status", "Submitted"))));
Running the java code returns all status logs and not the one that I am looking for.
Any help would be highly appreciated.
elemMatch should be in find method not in projection bson. For example:
collection.find(elemMatch("statusLog", eq("status", "Submitted"))).projection(projection);
You should use newer Document/MongoCollection api and use helper methods to prepare projection.
import static com.mongodb.client.model.Filters.eq;
import static com.mongodb.client.model.Projections.*;
MongoClient mongoClient = new MongoClient();
MongoDatabase database = mongoClient.getDatabase("db"); // Get DB
MongoCollection<Document> collection = database.getCollection("collection"); // Get Collection
Bson projection = Projections.fields( excludeId(), include("createdDate"), elemMatch("statusLog", eq("status", "Submitted"))); // Add Projections
FindIterable<Document> iterable = collection.find().projection(projection);
Using old BasicDBObject/DBCollection api
MongoClient mongoClient = new MongoClient();
DB database = mongoClient.getDB("db");
DBCollection collection = database.getCollection("collection");
BasicDBObject projection = new BasicDBObject(new BasicDBObject("statusLog",new BasicDBObject("$elemMatch", new BasicDBObject("status", "Submitted"))));
collection.find(new BasicDBObject(), projection);
To find an item in a list of document with multiple objects, using multiple filtrer criteria:
"array_of_data": {$elemMatch: {"AAA": "xxxx", "BBB": "xxxxx"}}

How to execute queries with both AND and OR clauses in MongoDB with Java?

I want to execute query in MongoDB 3.2 with Java Driver 3.2, which contains both $and and $or clauses at the same time.
With the reference, I tried the following approach:
List<Document> criteria1 = new ArrayList<>();
List<Document> criteria2 = new ArrayList<>();
criteria1.add(new Document("fetchStatus", new Document("$gte", FetchStatus.PROCESSED_NLP.getID())));
criteria1.add(new Document("fetchStatus", new Document("$lte", fetchStatusParam)));
criteria1.add(new Document("episodeID", new Document("$in", episodeIDs)));
criteria2.add(new Document("fetchStatus", new Document("$eq", PROCESSED_FETCH.getID())));
criteria2.add(new Document("isFullTextRet", new Document("$eq", false)));
BasicDBList or = new BasicDBList();
or.add(criteria1);
or.add(criteria2);
DBObject query = new BasicDBObject("$or", or);
ArrayList<Document> results = dbC_Coll.find(query).into(new ArrayList<>());
Where the criteria1 and criteria2 should be connected with $or while within criteria1 clause the $and should be applied.
The problem is that in MongoDB Java Driver 3.2 there is such no method and I get the Cannot resolve method find(com.mongodb.DBObject) error.
How can I compose a query such as (A && B) || (X && Y) in MongoDB Java Driver 3.2?
Personally, I find it far less confusing to construct the object sequences just like U would with a JSON structure to enhance readability. But it's still just Document() wherever you see {} and List wherever you see []:
Document query = new Document(
"$or", Arrays.asList(
// First document in $or
new Document(
"fetchStatus",
new Document( "$gte", FetchStatus.PROCESSED_NLP.getID() )
.append("$lte", fetchStatusParam)
)
.append("episodeID", new Document( "$in", episodeIDs)),
// Second document in $or
new Document("fetchStatus", PROCESSED_FETCH.getID())
.append("isFullTextRet", false)
)
);
Which is basically the same as:
{
"$or": [
{
"fetchStatus": {
"$gte": FetchStatus.PROCESS_NLP.getID(),
"$lte": fetchStatusParam
},
"episodeID": { "$in": episodeIDs }
},
{
"fetchStatus": PROCESSED_FETCH.getID(),
"isFullTextRet": false
}
]
}
Also there is no need for "explicit" $eq operators, since "equals" is actually the default meaning of a value assignment in a query property anyway.

mongodb mongoTemplate get distinct field with some criteria

My MongoDB json structure is
{
"_id" : "122134231234234",
"name" : "Total_pop",
"description" : "sales category",
"source" : "public",
"dataset" :"d1"
},
{
"_id" : "1123421231234234",
"name" : "Total_pop",
"description" : "sales category",
"source" : "public",
"dataset" :"d1"
},
{
"_id" : "12312342332423343",
"name" : "Total_pop",
"description" : "sales category",
"source" : "private",
"description" : "d1"
}
I need to get collection distinct of dataset where source is public.
I tried this query, and it didn't work:
Criteria criteria = new Criteria();
criteria.where("source").in("public");
query.addCriteria(criteria);
query.fields().include("name");
query.fields().include("description");
query.fields().include("description");
query.fields().include("source"); List list =
mongoTemplate.getCollection("collectionname").distinct("source", query);
Can you please help me out?
For one thing the .getCollection() method returns the basic Driver collection object like so:
DBCollection collection = mongoTemplate.getCollection("collectionName");
So the type of query object might be different from what you are using, but there are also some other things. Namely that .distinct() only returns the "distint" values of the key that you asked for, and doe not return other fields of the document. So you could do:
Criteria criteria = new Criteria();
criteria.where("dataset").is("d1");
Query query = new Query();
query.addCriteria(criteria);
List list = mongoTemplate.getCollection("collectionName")
.distinct("source",query.getQueryObject());
But that is only going to return "sample" as a single element in the list for instance.
If you want the "fields" from a distinct set then use the .aggregate() method instead. With either the "first" occurances of the other field values for the distinct key:
DBCollection colllection = mongoTemplate.getCollection("collectionName");
List<DBObject> pipeline = Arrays.<DBObject>asList(
new BasicDBObject("$match",new BasicDBObject("dataset","d1")),
new BasicDBObject("$group",
new BasicDBObject("_id","$source")
.append("name",new BasicDBObject("$first","$name"))
.append("description", new BasicDBObject("$first","$description"))
)
);
AggregationOutput output = colllection.aggregate(pipeline);
Or the actual "distinct" values of multiple fields, by making them all part of the grouping key:
DBCollection colllection = mongoTemplate.getCollection("collectionName");
List<DBObject> pipeline = Arrays.<DBObject>asList(
new BasicDBObject("$match",new BasicDBObject("dataset","d1")),
new BasicDBObject("$group",
new BasicDBObject("_id",
new BasicDBObject("source","$source")
.append("name","$name")
.append("description","$description")
)
)
);
AggregationOutput output = colllection.aggregate(pipeline);
There are also a direct .aggregate() method on mongoTemplate instances already, which has a number of helper methods to build pipelines. But this should point you in the right direction at least.
As of Spring Data Mongo 2.2.0 MongoTemplate provides a function to retrieve the distinct field with criteria,
Criteria criteria = new Criteria("country").is("IN");
Query query = new Query();
query.addCriteria(criteria);
return mongoTemplate.findDistinct(query,"city",Address.class,String.class);
Which basically finds all the distinct cities in address collection where country is IN.

Updating value of a subfield in MongoDB with Java driver?

I've quite new to MongoDB and it's Java driver.
I need to update the value of a subfield, but I can't find any examples online.
The document:
{
"_id" : ObjectId("45678942342"),
"user" : "me",
"aStruct" : {
"subfield_1" : true,
"subfield_2" : true
}
}
How do I update the value of subfield subfield_1 to false, for every document that has user = me ?
Thank you.
You can do it as follows :
db.collection.update({user : "me"},{$set:{"aStruct.subfield_1" : false}}, false, true)
In Java you can do it as follows :
DBCollection coll = // Define your collection here
DBObject query = new BasicDBObject();
query.put("user", "me");
DBObject updateObj = new BasicDBObject();
updateObj.put("aStruct.subfield_1", false);
coll.updateMulti(query, new BasicDBObject("$set", updateObj));
For more information read the following document.
Update document in MongoDB

Mongodb Java - How to return restricted fields with find() or findOne()

With the driver Java Mongodb, I am looking for a way to return just restricted fields with a
find() or findOne().
For example, I have a collection "people" with fields : "id", "name", "surname", "address", "city"... and I just want to return "name" and "surname"
I searched on the Web and I just found this example of code Java Mongodb : http://vsbabu.org/mt/archives/2010/03/02/simple_mongodbjava_example.html
If you are using Java Driver 3.1, you can use Projections:
collection.find().projection(Projections.include("name", "surname"));
You can pass another DBObject with the names of the fields and pass it here:
cur = coll.find(new BasicDBObject("id", 6655), your_dbobject_with_field_names);
Here is the API documentation
This codes will handle your problem.(java driver 3.0.2)
BasicDBObject fields = new BasicDBObject();
fields.put("title", 1);
DBCursor cursor = collection.find(new BasicDBObject(),fields).sort(new BasicDBObject("_id", 1));
this code run for me:
String json = "{_id:0,name:1,surname:1}";
Bson bson = BasicDBObject.parse( json );
FindIterable<Document> iterDoc = collection.find().projection(bson);

Categories