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);
Related
Currently I'm able to group based on filePrefix and getting the record with max fileId.
In the Output, I'm able to get the filePrefix and fileId, but unable to get fileName along with filePrefix and fileId.
Can anyone please help me out regarding this ...
My documents:
{
"_id" : ObjectId("58cbe224238b3953da3bc0bc"),
"fileName" : "samplefile1_124.txt",
"filePrefix":"samplefile1",
"fileId":124
}
{
"_id" : ObjectId("58cbe257238b3953da3bc0bd"),
"fileName" : "samplefile2_125.txt",
"filePrefix":"samplefile2",
"fileId":125
}
{
"_id" : ObjectId("58cf8d13f731b796bc343726"),
"fileName" : "samplefile3_126.dat",
"filePrefix":"samplefile3",
"fileId":126
}
{
"_id" : ObjectId("58cfa525f731b796bc343727"),
"fileName" : "samplefile1_126.txt",
"filePrefix":"samplefile1",
"fileId":126
}
{
"_id" : ObjectId("58cfa525f731b796bc343728"),
"fileName" : "samplefile2_127.txt",
"filePrefix":"samplefile2",
"fileId":127
}
My code:
MongoClient mongo = new MongoClient("localhost",27017);
MongoDatabase db = mongo.getDatabase("fileDB");
MongoCollection<Document> col = db.getCollection("fileStatus");
List<String> docsList = new ArrayList<>();
docsList.add("samplefile1");
docsList.add("samplefile2");
docsList.add("samplefile3");
Set<String> docsSet = new HashSet<>();
for(String st: docsList){
docsSet.add(st);
}
Document match = new Document("$match", new Document("filePrefix",new Document("$in",docsSet)));
Document group = new Document("$group" , new Document("_id","$filePrefix").append("fId", new Document("$max","$fileId")));
Document project = new Document("$project",new Document("filePrefix","$_id").append("fileId", "$fId"));
AggregateIterable<Document> output = col.aggregate(Arrays.asList(match,group,project));
for (Document dbObject : output)
{
System.out.println(dbObject);
}
My output:
Document{{_id=samplefile1, filePrefix=samplefile1, fileId=126.0}}
Document{{_id=samplefile2, filePrefix=samplefile2, fileId=127.0}}
Document{{_id=samplefile3, filePrefix=samplefile3, fileId=126.0}}
You'd need to run the following aggregate pipeline which sorts the documents first before applying the group operation as you need to use the $first (if in descending order) or $last (if in ascending) operator should you wish to return other fields. This in essence will give you the max field as well as the corresponding document fields.
For example using the sample documents as the input
db.test.aggregate([
{ "$match": { "filePrefix": { "$in": docsSet } } },
{ "$sort": { "filePrefix": 1, "fileId": -1 } },
{
"$group": {
"_id": "$filePrefix",
"fileId": { "$first": "$fileId"},
"fileName": { "$first": "$fileName"}
}
}
])
i.e. translated as
Document match = new Document(
"$match", new Document("filePrefix",
new Document("$in", docsSet)
)
);
Document sort = new Document("$sort",
new Document("filePrefix", 1).append("fileId", -1)
);
Document group = new Document("$group" ,
new Document("_id", "$filePrefix")
.append("fileId", new Document("$first", "$fileId")
.append("fileName", new Document("$first", "$fileName")
)
);
Document project = new Document("$project",
new Document("filePrefix", "$_id")
.append("fileId", 1)
.append("fileName", 1)
);
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);
}
}
}
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.
I want to return multiple questionElements where the questionElements metaTag entry equals my search. E.G. if a metaTag element equals my string the return it's parent questionEntry element and search across all elements nested in show.
{
"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'm usingthe latest Java Mongo driver in Windows 8.1 and using Mongodb 2.4.4. So my question is what is the best method to return a single or multiple qestionEntry element(s) over this entire show collection that match my search string?
Hopefully somebody here can help me with this.
EDIT:
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");
Please try the below :
db.exp.aggregate([{"$redact":{"$cond": { if: {$gt:[ {"$size": {
$setIntersection : [ { "$ifNull": [ "$metaTags", []]},
["House Stark"]]} } , 0 ]} , then:"$$PRUNE",
else:"$$DESCEND" }}}]).pretty();
[OR]
EDIT :
db.exp.aggregate([{"$unwind":"$show"},
{"$unwind":"$show.season"},
{"$unwind":"$show.season.episodes"},
{"$match" : {"show.season.episodes.questionEntry.metaTags":{"$in":
["Trivia"]}}},
{"$group":{"_id":"$_id","episodes":{"$push":"$show.season.episodes"}
]);
JAVA CODE :
MongoClient client = new MongoClient();
List<String> continentList = Arrays.asList(new String[]{"Trivia"});
DB db = client.getDB("example");
DBCollection coll = db.getCollection("exp");
DBObject matchFields = new
BasicDBObject("show.season.episodes.questionEntry.metaTags",
new BasicDBObject("$in", continentList));
DBObject groupFields = new BasicDBObject( "_id",
"$_id").append("episodes",
new BasicDBObject("$push","$show.season.episodes"));
DBObject unwindshow = new BasicDBObject("$unwind","$show");
DBObject unwindsea = new BasicDBObject("$unwind", "$show.season");
DBObject unwindepi = new BasicDBObject("$unwind",
"$show.season.episodes");
DBObject match = new BasicDBObject("$match", matchFields);
DBObject group = new BasicDBObject("$group", groupFields);
AggregationOutput output =
coll.aggregate(unwindshow,unwindsea,unwindepi,match,group);
for (DBObject result : output.results()) {
System.out.println(result);
}
I am new at MongoDB and I want to insert to mongodb data like this but I couldn't figure out how
{
image = "cab"
tags = [
[ "NNP", 0 ],
[ "NN", 1 ]
]
},
{
image = "castle"
tags = [
[ "NNP", 2 ],
[ "NN", 1 ],
]
}
my code is
BasicDBObject obj = new BasicDBObject();
obj.put("images", ....);
for(Tag tag:tags){
BasicDBObject tagsObj = new BasicDBObject();
tagsObj.put("NNP",tag.getNNP());
tagsObj.put("NN",tag.getNN());
obj.put("tags",tagsObj);
}
UPDATE:
using this code
Mongo m = new Mongo();
DB db = m.getDB("test");
DBCollection coll = db.getCollection("tags");
for(Tag tag:tags){
BasicDBList dbl = new BasicDBList();
dbl.add(new BasicDBObject("NNP",tag.getNNP()));
dbl.add(new BasicDBObject("NN", tag.getNNP()));
BasicDBObject outer=new BasicDBObject("images", currentImageName).append("tags", dbl);
coll.insert(outer);
}
I store every image alone cause the tags might be like this for the same image
{
image = "cab",
tags = [
{ "NNP", 0 },
{ "NN", 1 }
],
[ {"NNP", 4 },
{ "NN", 5 }
],
[
{"NNP", 0 },
{ "NN", 4 }
]
},
Thanks
Basically you use BasicDBObject for key-value mappings and BasicDBList for array objects. For the object in your question, you'd do this:
BasicDBList dbl = new BasicDBList();
dbl.add(new BasicDBObject("NNP",0));
dbl.add(new BasicDBObject("NN", 1));
BasicDBOBject outer=new BasicDBObject("image", "cab").append("tags", dbl);
There's some convenience methods in the api to make this a bit less verbose.
The mapping works like this:
for: {"A":1} use: new BasicDBObject("A",1)
for: {"A":1, "B":2} use: new BasicDBObject("A",1).append("B",2)
for: {"A":{"B":2}} use: new BasicDBObject("A",new BasicDBObject("B",2))
for: {"A":["B","C"]} use:
BasicDBList dbl = new BasicDBList();
dbl.add("B");
dbl.add("C");
-> new BasicDBObject("A",dbl);
Did you mean like this?
BasicDBObject obj = new BasicDBObject();
obj.put("image", ....);
for(Tag tag:tags){
BasicDBObject tagsObj = new BasicDBObject();
tagsObj.put("NNP",tag.getNNP());
tagsObj.put("NN",tag.getNN());
obj.put("tags",tagsObj);
}
Here is how i use it when using mongo3.x:
suppose you want the result to be like this: {"data": [{"key":"v1"}, {"key":"v1"}, {"key":"v1"}] }
[step1]: use Java Map to create json object which maps to the elements inside the array; that is, the {} inside []
[step1 Ans]: Map m1,m2,m3 = new HashMap(); m1.put("key", "v1"); m2.put("key", "v1"); m3.put("key", "v1");
[step2]: use Java List to add all Java Map into one element.
[step2 Ans]: List list = new ArrayList(); list.add(m1); list.add(m2); list.add(m3);
[step3]: add Java list into mongo
[step3 Ans]: Document dc = new Document("key", list);