Return random elements nested in mongo document - java

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 }

Related

Use $pull with $ne in java

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);

Retrieve mongodb array element using java

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
}

MongoDb Java Driver v3.x and aggregation framework

I have a collection containing contacts and each contact document has a firstName and lastName attribute.
Now I want to query the database by using Java and the MongoDb Java driver in version 3.2.
I try to find a contact with a concatenated firstName + lastName. My query looks like the following for the MongoDb shell:
db.getCollection('contacts').aggregate(
{
$project:{
fullName:{
$concat: [ "$firstName", " ", "$lastName" ]
}
}
},
{
$match:{
fullName:"John Doe"
}
}
);
Now I tried to get my head around the MongoDb Java driver to get the same accomplished in Java:
AggregateIterable<Document> documents = contactUserCollection.aggregate(Arrays.asList(project(computed("fullName", "$firstName $lastName")), match(eq("fullName", firstLastName))));
But this isn't working.
Does someone have an idea how I could accomplish this?
Thank you
You could try the following:
/*
MONGO SHELL :
var pipeline = [
{
"$project": {
"otherfieldsA": 1,
"otherfieldsB": 1,
"otherfieldsC": 1,
"fullName": {
"$concat": [ "$fistName", " ", "$lastName" ]
}
}
}
{
"$match": { "fullName": "John Doe" }
}
];
db.contacts.aggregate(pipeline);
*/
public class JavaAggregation {
public static void main(String args[]) throws UnknownHostException {
MongoClient mongo = new MongoClient();
DB db = mongo.getDB("test");
DBCollection coll = db.getCollection("contacts");
// create the pipeline operations, build the $project operations
BasicDBList concatenate = new BasicDBList();
concatenate.add("$firstName");
concatenate.add(" ");
concatenate.add("$lastName");
DBObject fullName = new BasicDBObject("$concat", concatenate);
DBObject fields = new BasicDBObject("otherfieldsA", 1);
fields.put("otherfieldsB", 1);
fields.put("otherfieldsC", 1);
fields.put("fullName", fullName);
DBObject project = new BasicDBObject("$project", fields);
// create the $match operator
DBObject match = new BasicDBObject("$match",
new BasicDBObject("fullName", "John Doe")
);
AggregationOutput documents = coll.aggregate(match, project, group, sort);
for (DBObject result : documents.results()) {
System.out.println(result);
}
}
}

Retrive a set of documents from array in MongoDB using Java driver

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();
}
}

Query fields in a MongoDB Collection.

I am trying to query specific fields in a mongodb collection. Here is my code and output:
Mongo m = new Mongo();
DB db = m.getDB( "mydb" );
DBCollection coll = db.getCollection("student") ;
// adding data
BasicDBObject moz = new BasicDBObject();
moz.put("Name", "Mozammil");
coll.insert(moz);
DBCursor cursor = coll.find();
while (cursor.hasNext()) {
System.out.println(cursor.next());
}
This returns the following:
{ "_id" : { "$oid" : "4f5a4477c5e80f71ece56797"} , "Name" : "Mozammil"}
However, i want only the Name part. Googling around, this should do the job.
DBCursor cursor = coll.find({}, {'Name':1});
while (cursor.hasNext()) {
System.out.println(cursor.next());
}
But it is not working. Help please?
You can use get on the returned document by the cursor to get the field you are looking for. Like this:
System.out.println(cursor.next().get("key"));
I know you already accepted an answer, but it isn't exactly what you were asking for.
Here is some working code:
// get Mongo set up...
Mongo m = new Mongo();
DB db = m.getDB( "test" );
DBCollection coll = db.getCollection("test");
// insert a test record
coll.insert(new BasicDBObject("Name","Wes").append("x", "to have a second field"));
// create an empty query
BasicDBObject query = new BasicDBObject();
// configure fields to be returned (true/1 or false/0 will work)
// YOU MUST EXPLICITLY CONFIGURE _id TO NOT SHOW
BasicDBObject fields = new BasicDBObject("Name",true).append("_id",false);
// do a query without specifying fields (and print results)
DBCursor curs = coll.find(query);
while(curs.hasNext()) {
DBObject o = curs.next();
System.out.println(o.toString());
}
// do a query specifying the fields (and print results)
curs = coll.find(query, fields);
while(curs.hasNext()) {
DBObject o = curs.next();
System.out.println(o.toString());
}
The first query outputs:
{ "_id" : { "$oid" : "4f5a6c1603647d34f921f967"} , "Name" : "Wes" , "x" : "to have a second field"}
And the second query outputs:
{ "Name" : "Wes"}
Take a look at DBCollection.find
BasicDBObject query = new BasicDBObject(); // because you have no conditions
BasicDBObject fields = new BasicDBObject("Name",1);
coll.find(query, fields);
collection.find().projection(Projections.include("Name"))
this worked such well!!!
BasicDBObject query = new BasicDBObject();
BasicDBObject fields = new BasicDBObject();
fields.put("name", 1);
DBCursor cursor = collection.find(query, fields);
while (cursor.hasNext()) {
System.out.println(cursor.next());
}
To get all nested keys:
public static ArrayList<String> getKeys(Document it1) throws JSONException {
ArrayList<String> result = new ArrayList<String>();
ArrayList<String> resultTemp;
String temp;
Document doc;
JSONArray jsa;
int len, i;
System.out.println(it1);
String js = it1.toJson();
JSONObject js1 = new JSONObject(js);
Iterator<String> keys = js1.keys();
while (keys.hasNext()) {
String key = keys.next();
if (key.equals("_id")) {
result.add(key);
continue;
}
System.out.println(key);
temp = js1.get(key).toString();
if (temp.contains(":")) {
jsa = new JSONArray(temp);
len = jsa.length();
for (i = 0; i < len; i++) {
JSONObject object = jsa.getJSONObject(i);
doc = Document.parse(object.toString());
System.out.println(doc);
resultTemp = getKeys(doc);
for (String keyTemp : resultTemp) {
if (!result.contains(key + "." + keyTemp))
result.add(key + "." + keyTemp);
}
}
} else {
result.add(key);
}
}
return result;
}
db.getCollection('users').aggregate([
{"$project":{"arrayofkeyvalue":{"$objectToArray":"$$ROOT"}}},
{"$unwind":"$arrayofkeyvalue"},
{"$group":{"_id":null,"columns":{"$addToSet":"$arrayofkeyvalue.k"}}}
])
Use the above query it will give you all the fields of a document. In this you will get nested field also.

Categories