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