Java MongoDB queries, inserting 2 '$or' conditions - java

I am trying to generate a MongoDB query with Java like the following:
{
"$or": [
{
"user": {
"$exists": true
}
},
{
"parent": {
"$exists":true
}
}
],
"working": 1,
"$or": [
{
"car.id": 3846,
"car.mediaType": 1
},
{
"car.matched.id": 3846,
"car.matched.model": 1
}
]
}
But I cannot do it because when the second $or condition is being added, the first one is overwritten.
I need to search with some of the results of each $or, I can't add it in the same $or. The code is:
import com.mongodb.BasicDBList;
import com.mongodb.BasicDBObject;
import com.mongodb.BasicDBObjectBuilder;
public class Sample {
public function mongoSearch()
{
BasicDBObjectBuilder queryBuidlerType = BasicDBObjectBuilder.start().add("working", 1);
BasicDBObject user = new BasicDBObject("user", new BasicDBObject("$exists", true));
BasicDBObject parent = new BasicDBObject("parent", new BasicDBObject("$exists", true));
BasicDBObject car = new BasicDBObject();
parentMatch.put("car.id", mId);
parentMatch.put("car.model", mModel);
BasicDBObject carMatched = new BasicDBObject();
parentMatch.put("car.matched.id", mId);
parentMatch.put("car.matched.model", mModel);
BasicDBList or1 = new BasicDBList();
or.add(user);
or.add(parent);
BasicDBList or2 = new BasicDBList();
or.add(car);
or.add(carMatched);
queryBuidlerType.add("$or", or1).add("$or", or2);
DBObject queryType = queryBuidlerType.get();
}
}

You should use $and wrapping both $or :
{
"$and": [
{"$or": [
{
"user": {
"$exists": true
}
},
{
"parent": {
"$exists":true
}
}
]},
{"$or": [
{
"car.id": 3846,
"car.mediaType": 1
},
{
"car.matched.id": 3846,
"car.matched.model": 1
}
]}
],
"working": 1
}
And also, I don't know what you're trying to do, but if you want to match "car.id": 3846" AND "car.mediaType": 1 in the same sub-object, consider using `$elemMatch
In Java :
QueryBuilder queryBuidlerType = QueryBuilder.start("working").is(1);
DBObject or1 = QueryBuilder.start().or(QueryBuilder.start("user").exists(true).get(), QueryBuilder.start("parent").exists(true).get()).get();
DBObject or2 = QueryBuilder.start().or(QueryBuilder.start("car.id").is(mId).and("car.model").is("mModel").get(), QueryBuilder.start("car.matched.id").is(mId).and("car.matched.model").is("mModel").get()).get();
queryBuidlerType.and(or1, or2);
DBObject queryType = queryBuidlerType.get();

Related

MongoDB document update array element using findOneAndUpdate method in Java

Can someone look at this issue as we are not able to insert the array in the field 'd' as shown in the image below:
[![JSON Structure in MongoDB][1]][1]
{
"id": 12,
"articles": "art",
"author": "author"
}
You have to use arrayFilters to update a specific array element (with a condition). The array filters in Java is defined with FindOneAndUpdateOptions object.
List<Bson> arrFilters = new ArrayList<>();
arrFilters.add(new Document("elem.apn", "abcdef")); // this specifies the element search criteria
FindOneAndUpdateOptions updateOptions = new FindOneAndUpdateOptions().arrayFilters(arrFilters);
String [] dArray = { "app", "ban", "ora" }; // the "d" array to be added
Bson update = set("session.ps.$[elem].d", Arrays.asList(dArray));
String idStr = "5e37dc262f5ff4dfc935eb6b";
Bson queryFilter = eq("_id", new ObjectId(idStr));
Document result = coll.findOneAndUpdate(queryFilter, update, updateOptions);
System.out.println(result);
The same update operation in Mongo Shell:
var dArray = [ "app", "ban" ];
db.test.updateOne(
{ _id: ObjectId("5e37dc262f5ff4dfc935eb6b") },
{ $set: { "session.ps.$[elem].d" : dArray } },
{
arrayFilters: [ { "elem.apn": "abcdef" } ]
}
)
[EDIT ADD]
Updating the apn simultaneously with a new value "newVal" and adding a new string element "gua" to the d array (this will add a new array if the array doesn't exist):
db.test.updateOne(
{ _id: ObjectId("5e37dc262f5ff4dfc935eb6b") },
{
$set: { "session.ps.$[elem].apn": "newVal" }
$push: { "session.ps.$[elem].d" : "gua" }
},
{
arrayFilters: [ { "elem.apn": "abcdef" } ]
}
)
The Java code for the above Mongo Shell code:
List<Bson> arrayFilters = new ArrayList<>();
arrayFilters.add(new Document("elem.apn", "abcdef"));
FindOneAndUpdateOptions updateOptions =
new FindOneAndUpdateOptions().arrayFilters(arrayFilters);
Bson pushUpdate = push("session.ps.$[elem].d", "gua");
Bson setUpdate = set("session.ps.$[elem].apn", "newValue");
Bson update = combine(pushUpdate, setUpdate);
String idStr = "5e37dc262f5ff4dfc935eb6b";
Bson queryFilter = eq("_id", new ObjectId(idStr));
Document result = coll.findOneAndUpdate(queryFilter, update, updateOptions);

Project using array fields in MongoDB Java Driver

I have Collection as following. I have query this collection by user.
{
"user": "username",
"sites": {
"site": "abc",
"keywords": [
{
"keyword": "keyword1",
"dailyranks": [
{
"fild1": "value1"
},
{
"fild2": "value2"
},
{
"fild3": "value3"
},
]
},
{
"keyword": "keyword2",
"dailyranks": [
{
"fild1": "value1"
},
{
"fild2": "value2"
},
{
"fild3": "value3"
},
]
},
],
}
}
I want to get the result from the collection as follows, I want to get the last elements of keyword array in the collection
[
{
"keyword" : "keyword1"
"fild2" : "value2",
"fild3" : "value3"
},
{
"keyword" : "keyword2"
"fild2" : "value2",
"fild3" : "value3"
},
]
I have aggregate using $project, but didn't work out. help me to sort this out.
Code used-
BasicDBObject siteObject = new BasicDBObject();
siteObject.append("keywords", "$sites.keywords.keyword");
siteObject.append("lastrank", "$sites.keywords.dailyranks");
BasicDBList aDBList = new BasicDBList();
aaa.add(new BasicDBObject("user", modelLogin.getUSER_NAME()));
ArrayList<BasicDBObject> doc = new ArrayList<>();
doc.add(new BasicDBObject().append("$unwind", "$sites"));
doc.add(new BasicDBObject("$match", aDBList));
doc.add(new BasicDBObject().append("$project", siteObject));
AggregationOutput output = coll.aggregate(doc);
You can try below aggregation.
Use $map to transform the Keywords array.
Within $map, use $arrayElemAt to project the last and second last values from dailyranks and $let operator to hold the result from $arrayAtElem and project the fild value.
db.coll.aggregate({
$project: {
keywords: {
$map: {
input: "$sites.keywords",
as: "result",
in: {
keyword: "$$result.keyword",
fild2: {$let: {vars: {obj: {$arrayElemAt: ["$$result.dailyranks", -2]}},in: "$$obj.fild2"}},
fild3: {$let: {vars: {obj: {$arrayElemAt: ["$$result.dailyranks", -1]}},in: "$$obj.fild3"}}
}
}
}
}
})
Java Equivalent
MongoClient mongoClient = new MongoClient();
MongoDatabase db = mongoClient.getDatabase("db")
MongoCollection<Document> collection = db.getCollection("collection");
List<Document> results =
collection.aggregate(
Arrays.asList(
Aggregates.match(Filters.eq("user", modelLogin.getUSER_NAME() )),
Aggregates.project(
Projections.fields(
new Document("keywords",
new Document("$map",
new Document("input", "$sites.keywords").
append("as", "result").
append("in",
new Document("keyword","$$result.keyword").
append("fild2",
new Document("$let",
new Document("vars", new Document("obj",
new Document("$arrayElemAt", Arrays.asList("$$result.dailyranks", -2)))).
append("in", "$$obj.fild2" ))).
append("fild3",
new Document("$let",
new Document("vars", new Document("obj",
new Document("$arrayElemAt", Arrays.asList("$$result.dailyranks", -1)))).
append("in", "$$obj.fild3" )))
)
)
)))
)).into(new ArrayList<>());

MongoDB average value of attribute of embedded array (using Java and MongoJack)

I have a collection named "Restaurants" which looks like this:
{
"_id" : ObjectId("51236fbc3004f02f87c62e8e"),
"name" : "Some very fancy name"
reviews: [
{"id" : 1,
"text" : "saffas"
"rating" : 3,
}
{"id" : 2,
"text" : "fsafasfas"
"rating" : 4,
}
]
}
I would like to get an average rating of all of the reviews of the restaurant. How can I do this (I use Java)?
Run the following aggregation pipeline to get the average rating of a restaurant:
Mongo shell
var pipeline = [
{ "$unwind": "$reviews" },
{
"$group": {
"_id": "$name",
"avg_rating": { "$avg": "$reviews.rating" }
}
}
]
db.Restaurants.aggregate(pipeline);
This can be translated to Java as:
Java test implementation
public class JavaAggregation {
public static void main(String args[]) throws UnknownHostException {
MongoClient mongo = new MongoClient();
DB db = mongo.getDB("test");
DBCollection coll = db.getCollection("Restaurants");
// create the pipeline operations, first with the $unwind
DBObject unwind = new BasicDBObject("$unwind", "$reviews");
// build the $group operations
DBObject groupFields = new BasicDBObject("_id", "$name");
groupFields.put("avg_rating", new BasicDBObject("$avg", "$reviews.rating"));
DBObject group = new BasicDBObject("$group", groupFields);
List<DBObject> pipeline = Arrays.asList(unwind, group);
AggregationOutput output = coll.aggregate(pipeline);
for (DBObject result : output.results()) {
System.out.println(result);
}
}
}

How do I group the results of mongodb query and implement in Java?

I have a collection in a Mongo database that looks like this:
{
"_id" : ObjectId("561b42d4e4b0d4227d011d2c"),
"product_related_data" : {
"depth" : 6,
"height" : 23,
"product_barcode" : "54491472",
"product_name" : "xyz product",
"product_uuid" : "009b9846-b3ad-49f7-a7a0-d35a04f83480",
"width" : 6
},
"sensostrip_data" : {
"barcode" : "130150208299",
"battery_level" : 2.894
},
"stock_related_data" : {
"calculated_max_product_percentage" : 15.625,
"calculated_min_product_percentage" : 12.5,
"current_stock" : 2,
"max_stock" : 6,
"stock_difference_percentage" : 0,
"stock_difference_value" : 0,
"stock_percentage" : 37.5
},
"store_data" : {
"city_uuid" : "cbb4dfe8-172b-11e4-a1f0-00163ed23ec2",
"ip" : "10.0.1.1",
"retailer_uuid" : "8c33c32c-5903-11e4-a1f0-00163ed23ec2",
"store_name" : "xyz store",
"store_uuid" : "15a6cc90-081f-11e5-b213-001e6745ff8d"
},
"time" : {
"check_date" : "2015-10-11 11:53:55",
"previous_check_date" : "2015-10-11 11:48:57"
},
"id" : "6be54bef-0aa3-456c-b912-1731f8154e7d"
}
The mongo query I'm currently executing returns all the documents for a list of store_uuid's and for a product_uuid, and looks like this:
db.readings
.find({ $and:[ {"store_data.store_uuid": {$in:["15a6cc90-081f-11e5-b213-001e6745ff8d","217b983b-5904-11e4-a1f0-00163ed23ec2","5337d78d-5904-11e4-a1f0-00163ed23ec2"]}}
,{"product_related_data.product_uuid": "f44aa29d-09ce-4902-bf12-d45d44b3dfd0"}]})
My current Java implementation (where I make use of projection) looks like this:
DBCollection table = databaseConncetion().getCollection("readings");
BasicDBObject sensorReturn = new BasicDBObject("sensostrip_data.barcode",1);
BasicDBObject clause1 = new BasicDBObject("store_data.store_uuid", new BasicDBObject("$in", StoreIds));
BasicDBObject clause2 = new BasicDBObject("product_related_data.product_uuid", productId);
BasicDBList and = new BasicDBList();
and.add(clause1);
and.add(clause2);
DBObject query = new BasicDBObject("$and", and);
DBCursor cursor = table.find(query, sensorReturn
.append("stock_related_data.stock_percentage",1)
.append("store_data.store_uuid",1)
.append("time.check_date", 1))
.sort(new BasicDBObject("time.check_date", -1))
.limit(100);
However I need this query to group the results for the latest check_date by barcode
The aggregation framework is at your disposal. Running the following aggregation pipeline will give you the desired result:
Mongo shell:
pipeline = [
{
"$match": {
"store_data.store_uuid": {
"$in": [
"15a6cc90-081f-11e5-b213-001e6745ff8d",
"217b983b-5904-11e4-a1f0-00163ed23ec2",
"5337d78d-5904-11e4-a1f0-00163ed23ec2"
]
},
"product_related_data.product_uuid": "f44aa29d-09ce-4902-bf12-d45d44b3dfd0"
}
},
{ "$sort": { "time.check_date": -1 } },
{
"$group": {
"_id": "$sensostrip_data.barcode",
"stock_percentage": { "$first": "$stock_related_data.stock_percentage" },
"store_uuid": { "$first": "$store_data.store_uuid" },
"check_date": { "$first": "$time.check_date" }
}
},
{ "$limit": 100 }
];
db.readings.aggregate(pipeline);
Java test implementation
public class JavaAggregation {
public static void main(String args[]) throws UnknownHostException {
MongoClient mongo = new MongoClient();
DB db = mongo.getDB("test");
DBCollection coll = db.getCollection("readings");
// create the pipeline operations, first with the $match
DBObject match = new BasicDBObject("$match",
new BasicDBObject("store_data.store_uuid", new BasicDBObject("$in", StoreIds))
.append("product_related_data.product_uuid", productId)
);
// sort pipeline
DBObject sort = new BasicDBObject("$sort",
new BasicDBObject("time.check_date", -1)
);
// build the $group operations
DBObject groupFields = new BasicDBObject( "_id", "$sensostrip_data.barcode"); // group by barcode
groupFields.put("stock_percentage", new BasicDBObject( "$first", "$stock_related_data.stock_percentage")); // get the first when ordered documents are grouped
groupFields.put("store_uuid", new BasicDBObject( "$first", "$store_data.store_uuid"));
groupFields.put("check_date", new BasicDBObject( "$first", "$time.check_date"));
// append any other necessary fields
DBObject group = new BasicDBObject("$group", groupFields);
// limit step
DBObject limit = new BasicDBObject("$limit", 100);
// put all together
List<DBObject> pipeline = Arrays.asList(match, sort, group, limit);
AggregationOutput output = coll.aggregate(pipeline);
for (DBObject result : output.results()) {
System.out.println(result);
}
}
}

Java mongodb - find then average

Okey, let's start. Imagine that we have the next mongo collection:
{
"city": "TWENTYNINE PALMS",
"loc": [-116.06041, 34.237969],
"pop": 11412,
"state": "CA",
"_id": "92278"
}
{
"city": "NEW CUYAMA",
"loc": [-74.823806, 34.996709],
"pop": 80,
"state": "CA",
"_id": "93254"
}
{
"city": "WATERBURY",
"loc": [-72.996268, 41.550328],
"pop": 25128,
"state": "CT",
"_id": "06705"
}
Notice that loc array is [latitude,longitude]
I would like to obtain using java mongo driver the "pop" average of the cities that have the altitude beetwen -75,-70.
So, using SQL I know that the query is:
SELECT avg(pop)
WHERE loc.altitude > -75 AND lloc.altitude < -70
I am very noob in mongodb, this is my current code:
BasicDBObject doc = new BasicDBObject("loc.0", new BasicDBObject("$gte",
-75).append("$lte", -70));
DBCursor cursor = collection.find(doc);
The previous code returns me all the documents that altitude are beetwen (-75,-70), but I do not know how to obtain the average,using mongo driver, I know that I can iterate over results using java..
Thank you
Use the aggregation framework with following aggregation pipeline (Mongo shell implementation):
db.collection.aggregate([
{
"$match": {
"loc.0": { "$gte": -75 },
"loc.1": { "$lte": 70 }
}
},
{
"$group": {
"_id": 0,
"average": {
"$avg": "$pop"
}
}
}
])
With the example above, this outputs to console:
/* 1 */
{
"result" : [
{
"_id" : 0,
"average" : 12604
}
],
"ok" : 1
}
With Java, this can be implemented as follows:
DBObject match = new BasicDBObject();
match.put("loc.0", new BasicDBObject("$gte", -75));
match.put("loc.1", new BasicDBObject("$lte", 70));
DBObject groupFields = new BasicDBObject( "_id", 0);
groupFields.put("average", new BasicDBObject( "$avg", "$pop"));
DBObject group = new BasicDBObject("$group", groupFields);
AggregationOutput output = collection.aggregate( match, group );

Categories