Use $pull with $ne in java - 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);

Related

Why CustomProjectAggregationOperation Not working in SpringMongoTemplate

I trying the following query in spring onto the template, that query works in Mongoserver, but when I using the query in the SpringMongo template, the filter does not work, it gets all date, instead of filters date. If anyone knows this issue. pls, help me out this.
The Native Mongo Query:-
db.Task_Status.aggregate([{
{"$addFields":{"timeDiff": { $floor: { $divide: [ { $subtract:[ new Date() , "$currenttime" ] } , 60000 ] } } }},
{$match:{$and:[{"timeDiff":{"$lt": 12}}]}} }]);
The Spring MongoTempalte java Code:
String nativeFilterQuery = "{\"$addFields\":{\"timeDiff\": { $floor: { $divide: [ { $subtract:[ new Date() , \"$currenttime\" ] } , 60000 ] } } }},{$match:{$and:[{\"timeDiff\":{\"$lt\": 12}}]}}";
List<TaskStatus> amTaskLists = Collections.EMPTY_LIST;
List<AggregationOperation> aggregationOperations = new ArrayList<>();
if (StringUtility.isNotNullOrEmpty(nativeFilterQuery)) {
aggregationOperations.add(new CustomProjectAggregationOperation(nativeFilterQuery));
}
TypedAggregation<TaskStatus> aggregation = Aggregation.newAggregation(TaskStatus.class, aggregationOperations);
AggregationResults result = execute(aggregation, TaskStatus.class);
amTaskLists = result.getMappedResults();
When I split the query and Run like following its works
String queryOne = "{\"$addFields\":{\"timeDiff\": { $floor: { $divide: [ { $subtract:[ new Date() , \"$currenttime\" ] } , 60000 ] } } }}";
String queryTwo = "{$match:{$and:[{\"timeDiff\":{\"$lt\": 12}}]}}";
List<AggregationOperation> aggregationOperations = new ArrayList<>();
if (StringUtility.isNotNullOrEmpty(queryOne)) {
aggregationOperations.add(new CustomProjectAggregationOperation(queryOne));
}
if (StringUtility.isNotNullOrEmpty(queryTwo)) {
aggregationOperations.add(new CustomProjectAggregationOperation(queryTwo));
}
You can use AggregationOperation for performing different aggregation in springmongo,but $addFields not support till 3.2 version for that use DBObject for creating query.
For example i used addFields to add score in textcriria my AggregationOperation is:
AggregationOperation score = new AggregationOperation() {
#Override
public DBObject toDBObject(AggregationOperationContext aggregationOperationContext) {
return new BasicDBObject(
"$addFields",
new BasicDBObject("score", new BasicDBObject("$meta","textScore"))
);
}
};
So you can use in your way to find timeDiff and also create match function and you can use like:
List<AggregationOperation> dataListopeartion = new ArrayList<>();
MatchOperation match = new MatchOperation(new Criteria().andOperator(Criteria.where("timeDiff").lte(12));
dataListopeartion.add(match);
dataListopeartion.add(score); //your timeDiff query with AggregationOperation
Aggregation agg = Aggregation.newAggregation(dataListopeartion);
AggregationResults<TaskStatus> groupResults = mongoTemplate.aggregate(agg, Task_Status,TaskStatus.class);
ListMongoWrapper<TaskStatus> mongoWrapper = groupResults.getMappedResults();
You can also refer following answer of SO for better understanding:
link1, link2

Return random elements nested in mongo document

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 }

How to write group by with add operation in MongoDB Java driver

In the following query , I'm doing addition to a field (This field having ISO date as value) then extracting hour from that field, then group by on hour
db.campaigns.aggregate([
{$group : { _id: {$hour:{$add:['$time', 19800000]}}}}
])
Sample record of the collection
db.campaigns.findOne()
{
"_id" : ObjectId("53c7afdab92be74745af9068"),
"time" : ISODate("2013-03-08T12:25:24.973Z"),
"type" : "annoying",
"PINGS" : 143
}
The above one is working fine in Mongo shell,
I'm trying write this query in Java
Here is my partial Java code
DBObject group2Fields = new BasicDBObject();
group2Fields.put("hour", new BasicDBObject("$hour", new BasicDBObject("$add",new BasicDBObject("time",19800000))));
DBObject group2 = new BasicDBObject("_id", group2Fields);
DBObject secondGroup = new BasicDBObject("$group", group2);
I'm getting "errmsg" : "exception: field inclusion is not allowed inside of $expressions"
try this:
DBObject group2Fields = new BasicDBObject();
BasicDBList addObjects = new BasicDBList();
addObjects.add("$time");
addObjects.add(19800000);
group2Fields.put("$hour", new BasicDBObject("$add", addObjects));
DBObject group2 = new BasicDBObject("_id", group2Fields);
DBObject secondGroup = new BasicDBObject("$group", group2);
Nesting calls in your code generally helps you to "visualise" the structure that you want:
BasicDBList addArgs = new BasicDBList();
addArgs.add("$time");
addArgs.add(19800000);
DBObject group = new BasicDBObject("$group",
new BasicDBObject("_id",
new BasicDBObject("$hour",
new BasicDBObject("$add", addArgs)
)
)
);
Which of course produces a group variable that serializes like so:
{ "$group" : { "_id" : { "$hour" : { "$add" : [ "$time" , 19800000]}}}}

Getting data from mongo db like we get in mysql?

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

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

Categories