I have a MongoDB document structure like this:
{
"name": "list"
"config": "default"
"items": [
{
"email": "user1#mail.com"
"status": true
"number": 123
},
...
{
"email": "user100#mail.com"
"status": false
"number": 432
},
]
}
Now, how can I retrive multiple subdocuments that much certain criteria. For instance, I want to obtain all documents where status = true. I know that it is possible to use $elemMatch, but it returns only the first matching instance and I need ALL documents that correspond to the specified condition. Please show how can it be done with Java.
You can do it in Java as follows.
Mongo mongo = new Mongo("localhost:27017");
DB db = mongo.getDB("myDB");
DBCollection coll = db.getCollection("myCollection");
DBObject statusQuery = new BasicDBObject("status", true);
DBObject elemMatchQuery = new BasicDBObject("$elemMatch", statusQuery);
DBObject fields = new BasicDBObject();
fields.put("items", elemMatchQuery);
fields.put("name", 1);
fields.put("config", 1);
DBCursor cur = coll.find(new BasicDBObject(), fields);
while (cur.hasNext()) {
DBObject obj = cur.next();
// Get fields from object
}
If you want all subdocuments from the list items in separate documents, you can $unwind the list. I also added filter matching status is true:
try (MongoClient client = new MongoClient()) {
MongoDatabase db = client.getDatabase("myDB");
MongoCollection<BsonDocument> collection = db.getCollection("myColl", BsonDocument.class);
MongoCursor<BsonDocument> cursor =
collection.aggregate(Arrays.asList(new Document("$unwind", "$items"),
new Document("$match", new Document("items.status", true)))).iterator();
try {
while (cursor.hasNext()) {
// I think this is what you need
BsonDocument bsonDocument = cursor.next().getDocument("items");
// and if you just want emails
String email = bsonDocument.get("email").asString().getValue();
System.out.println(email);
}
} finally {
cursor.close();
}
}
Related
I wrote this command in mongodb:
db.getCollection('bnaTask').update(
{"_id":ObjectId("5a2d21823be8c34e903245b7") },
{ $pull: { "status.events": { "event": { $ne: "mybnaCsvUploaderExecuted" } , "time": { $ne: "2017-12-10T11:58:53.543Z" } } } },
{ multi: true }
)
and I want to know how to write it in java, thanks.
Everything is Object in java. you are just constructing BSON objects to match their respective JSON counterparts as used in the segment.
BasicDBObject query = new BasicDBObject("_id", 73);
BasicDBObject event = new BasicDBObject("event", new BasicDBObject( "$ne",
"mybnaCsvUploaderExecuted");
BasicDBObject time = new BasicDBObject("time",
new BasicDBObject( "$ne","2017-12-10T11:58:53.543Z"));
Map<String,Object> map=new HashMap<String,Object>();
map.put("event",event);
map.put("time",time);
BasicDBObject fields = new BasicDBObject("status.events", map);
BasicDBObject update = new BasicDBObject("$pull",fields);
BasicDBObject multiple = new BasicDBObject("multi",true);
getCollection('bnaTask').update( query, update ,multiple);
I have this in my db.
{
"_id" : ObjectId("59424f41baaacf1f40815ae8"),
"first_name" : "Yazid",
"last_name" : "Amir",
"gender" : "Male",
"hobby" : ["Memanah", "Business", "Fusal", "Makan"]
}
Let say that I want to retrieve the "Business" from array hobby. So my code will be like this
MongoCollection collection = db.getCollection("customers");
BasicDBObject whereQuery = new BasicDBObject();
whereQuery.put("first_name", "Yazid");
MongoCursor<Document> cursor = collection.find(whereQuery).iterator();
try {
while (cursor.hasNext()) {
Document str = cursor.next();
out.println(str.get("hobby.0")); // display specific field
}
} finally {
cursor.close();
}
However, the result is null.
Use a List<Document> to store your array
while (cursor.hasNext()) {
Document str = cursor.next();
List<Document> list = (List<Document>)str.get("hobby");
out.println(list.get(0)); // display specific field
}
Hi I want to auto increment _id in mongodb using java. I am completely new to this. In the document I found the solution like this:
db.counters.insert(
{
_id: "userid",
seq: 0
}
)
function getNextSequence(name) {
var ret = db.counters.findAndModify(
{
query: { _id: name },
update: { $inc: { seq: 1 } },
new: true
}
);
return ret.seq;
}
db.users.insert(
{
_id: getNextSequence("userid"),
name: "Sarah C."
}
)
Can any one suggest how do I do this using java ? I am completely new to this.
Using Create an Auto-Incrementing Sequence Field first you should create collection using mongoDB shell and collection should be as :
db.counters.insert(
{
_id: "userid",
seq: 0
})
So you get counters collections which contains field like _id,seq, now create getNextSequence function in java and this function having parameter userid as string so getNextSequence function like this :
public static Object getNextSequence(String name) throws Exception{
MongoClient mongoClient = new MongoClient( "localhost" , 27017 );
// Now connect to your databases
DB db = mongoClient.getDB("demo");
DBCollection collection = db.getCollection("counters");
BasicDBObject find = new BasicDBObject();
find.put("_id", name);
BasicDBObject update = new BasicDBObject();
update.put("$inc", new BasicDBObject("seq", 1));
DBObject obj = collection.findAndModify(find, update);
return obj.get("seq");
}
The above function return seq count and used this function in main method as like :
public static void main(String[] args) throws Exception {
MongoClient mongoClient = new MongoClient( "localhost" , 27017 );
// Now connect to your databases
DB db = mongoClient.getDB("demo");
DBCollection collection = db.getCollection("counters");
BasicDBObject document = new BasicDBObject();
document.put("_id", getNextSequence("userid"));
document.put("name","Sarah C.");
collection.insert(document); // insert first doc
document.put("_id", getNextSequence("userid"));
document.put("name", "Bob D.");
collection.insert(document); // insert second doc
}
Now in counters collection contains three documents which contains name as Sarah C. and Bob D. respectively and one default documents which we inserted manually at first time and it increment seq like this { "_id" : "userid", "seq" : 2 }
DBCollection collection = database.getCollection("Table Name");
DBObject modifier = new BasicDBObject("counter", 1);
DBObject incQuery = new BasicDBObject("$id", modifier);
I has the following json document in Mongo db. The show element will have several season elements which will also have several episodes elements that in turn have multiple questionEntry elements.
{
"show":[
{
"season":[
{
"episodes":[
{
"questionEntry":{
"id":1,
"info":{
"seasonNumber":1,
"episodeNumber":5,
"episodeName":"A Hero Sits Next Door"
},
"questionItem":{
"theQuestion":"What is the name of the ringer hired by Mr. Weed?",
"attachedElement":{
"type":1,
"value":""
}
},
"options":[
{
"type":1,
"value":"Johnson"
},
{
"type":1,
"value":"Hideo"
},
{
"type":1,
"value":"Guillermo"
}
],
"answer":{
"questionId":1,
"answer":3
},
"metaTags":[
"Season 1",
"Episode 5",
"Trivia",
"Arya Stark",
"House Stark"
]
}
}
]
}
]
}
]
}
I have been able to return questionElement(s) where the questionElements metaTag entry equals my search. E.G. if a metaTag element equals my string then return the questionEntry element that the metaTag element resides in and search the whole show element and return all that match using this code:
(thanks to Yathish Manjunath for help with this piece of code)
private DB mongoDatabase;
private DBCollection mongoColl;
private DBObject dbObject;
// Singleton class
// Create client (server address(host,port), credential, options)
mongoClient = new MongoClient(new ServerAddress(host, port),
Collections.singletonList(credential),
options);
mongoDatabase = ClientSingleton.getInstance().getClient().getDB("MyDB");
queryMetaTags("Season 1");
//#SuppressWarnings("deprecation")
public void queryMetaTags(String query)
{
List<String> continentList = Arrays.asList(new String[]{query});
DBObject matchFields = new
BasicDBObject("show.season.questions.questionEntry.metaTags",
new BasicDBObject("$in", continentList));
DBObject groupFields = new BasicDBObject( "_id",
"$_id").append("questions",
new BasicDBObject("$push","$show.season.questions"));
//System.out.println("2");
DBObject unwindshow = new BasicDBObject("$unwind","$show");
DBObject unwindsea = new BasicDBObject("$unwind", "$show.season");
DBObject unwindepi = new BasicDBObject("$unwind",
"$show.season.questions");
DBObject match = new BasicDBObject("$match", matchFields);
DBObject group = new BasicDBObject("$group", groupFields);
#SuppressWarnings("deprecation")
AggregationOutput output =
mongoColl.aggregate(unwindshow,unwindsea,unwindepi,match,group);
String s = JSON.serialize(dbObject);
JSONObject json = null;
for (DBObject result : output.results())
{
System.out.println(result);
// pretty view for testing
try
{
json = new JSONObject(result);
System.out.println(json.toString(4));
}
catch (JSONException e1)
{
e1.printStackTrace();
}
}
System.out.println("In end of queryMetaTags");
}
I want to search like above but only return 10 random matching questionEntry elements? What is the best and most efficient way to achieve this?
I have to say I'm totally new to search queries for any database and just can't figure out how to achieve a slick solution? Hopefully somebody here can help with this.
You can use the $limit in the aggregation chain. Note that you have to add it as the last chain.
{ $limit: <positive integer> }
So in your case,
{ $limit: 10 }
I am inserting some value into mongodb in this way.
MongoClient mongo = new MongoClient( "localhost" , 27017 );
DB db = mongo.getDB("test");
DBCollection table = db.getCollection("paramDescMapper");
String key = UUID.randomUUID().toString();
String value = "{\"param0\":\"Car Make\",\"param1\":\"Car Model\",\"param2\":\"Car Variant\",\"param3\":\"Car Year\",\"param4\":\"Car Number\"}";
JSONObject jsonObject = new JSONObject(value);
// create a document to store key and value
BasicDBObject document = new BasicDBObject();
document.put("apiKey", key);
document.put("apiParamDesc", jsonObject.toString());
table.insert(document);
It is inserting data in this way.
{ "_id" : { "$oid" : "534251125f1ab7ec747298cd"} , "apiKey" : "1eb9b9e3-3af1-4b25-b7ea-1f2fcb1d9af6" , "apiParamDesc" : "{\"param0\":\"Car Make\",\"param1\":\"Car Model\",\"param2\":\"Car Variant\",\"param3\":\"Car Year\",\"param4\":\"Car Number\"}"}
Now i want to get apiParamDesc value using apiKey. Like how we get data in mysql.
Select apiParamDesc where apiKey =
'1eb9b9e3-3af1-4b25-b7ea-1f2fcb1d9af6';
I googled a lot but could not found anything. This is how i am trying to get this apiParamDesc
BasicDBObject whereQuery = new BasicDBObject();
whereQuery.put("apiKey", "1eb9b9e3-3af1-4b25-b7ea-1f2fcb1d9af6");
DBCursor cursor = table.find(whereQuery);
while(cursor.hasNext()) {
System.out.println(cursor.next());
}
But this is giving me entire row. I want only apiParamDesc in a String.
Please help me.
Thanks
You can easily do it with aggregation framework. Below is the example which can resolve your issue:
// create our pipeline operations, first with the $match
DBObject match = new BasicDBObject("$match", new BasicDBObject("apiKey", "1eb9b9e3-3af1-4b25-b7ea-1f2fcb1d9af6"));
// build the $projection operation
DBObject fields = new BasicDBObject("apiParamDesc", 1);
fields.put("_id", 0);
DBObject project = new BasicDBObject("$project", fields );
// run aggregation
AggregationOutput output = collection.aggregate( match, project);
You can also make use of only db.coll.find(< criteria >, < projection >);
BasicDBObject query = new BasicDBObject(new BasicDBObject("apiKey", "1eb9b9e3-3af1-4b25-b7ea-1f2fcb1d9af6"), new BasicDBObject("apiParamDesc", 1).append("_id", 0));
//Which is equivalent to a follwoing query
//'db.coll.find({"apiKey": "1eb9b9e3-3af1-4b25-b7ea-1f2fcb1d9af6"}, {"apiParamDesc": 1,"_id": 0});'
cursor = coll.find(query);
One more thing to update you on "I want only apiParamDesc in a String.", is if you are storing string like
"apiParamDesc" : "{\"param0\":\"Car Make\",\"param1\":\"Car Model\",\"param2\":\"Car Variant\",\"param3\":\"Car Year\",\"param4\":\"Car Number\"}
You cannot query on those sub level fields like param0, param1 ...
You data should look like :
{
"_id":{
"$oid":"534251125f1ab7ec747298cd"
},
"apiKey":"1eb9b9e3-3af1-4b25-b7ea-1f2fcb1d9af6",
"apiParamDesc":{
"param0":"Car Make",
"param1":"Car Model",
"param2":"Car Variant",
"param3":"Car Year",
"param4":"Car Number"
}
}
I want only apiParamDesc in a String.
You cannot however, you can get a document (object) returned with only the apiParamDesc as its single field (my Java is rusty):
BasicDBObject whereQuery = new BasicDBObject();
whereQuery.put("apiKey", "1eb9b9e3-3af1-4b25-b7ea-1f2fcb1d9af6");
BasicDBObject fields = new BasicDBObject();
fields.put("apiParamDesc", 1);
fields.put("_id", 0);
DBCursor cursor = table.find(whereQuery, fields);
while(cursor.hasNext()) {
System.out.println(cursor.next());
}