Mongodb query (hashmap objects) - mongodb

I want to query all the UserGroup's ID where admins's ID="25160228446835585906563830293" or users's ID ="25160228446835585906563830293".
this is a hashmap key and value pair in java obj hashmap<String,Date>
"25160228446835585906563830293" : ISODate("2013-03-26T04:51:36.731Z")
{ "_id" : ObjectId("51512958849ca4748271c640"),
"_class" : "com.pcd.app.model.UserGroup",
"groupName" : "sdfsadfsad",
"privacyType" : "PRIVACY_OPEN",
"approvalType" : "MEMBER_APPROVAL",
"groupDescription" : "test",
"admins" : {
"25160228446835585906563830293" : ISODate("2013-03-26T04:51:36.731Z"),
"25160228446835585906563830294" : ISODate("2013-03-26T04:51:36.731Z"),
"25160228446835585906563830295" : ISODate("2013-03-26T04:51:36.731Z")
},
"users" : {
"25160228446835585906563830296" : ISODate("2013-03-26T04:51:36.731Z")
}
}

I'd suggest you restructure your document to make it indexable and more easily searched in MongoDB.
Instead of using the id of the admin as a field, add each admin as an object of an array:
"admins" : [
{ id: "25160228446835585906563830293",
date: ISODate("2013-03-26T04:51:36.731Z") }
],
This will make searches more natural:
db.so.find( { "admins.id" :
{ $in: ['25160228446835585906563830293',
'25160228446835585906563830296']}})
You can use the $in (docs) operator to look for admins with an id that matches the list as you wanted (admins.id).
So, given a Java QueryBuilder, it might look something like this:
BasicDBList adminIds = new BasicDBList();
adminIds.addAll(ids); // the ids could be a List<String>
DBObject inClause = new BasicDBObject("$in", adminIds);
DBObject query = new BasicDBObject("admins.id", inClause);
You may want to use ensureIndex to build an index (docs).
Based on your original example, here's the full document for reference:
{
"_id" : ObjectId("51512958849ca4748271c640"),
"_class" : "com.pcd.app.model.UserGroup",
"groupName" : "sdfsadfsad",
"privacyType" : "PRIVACY_OPEN",
"approvalType" : "MEMBER_APPROVAL",
"groupDescription" : "test",
"admins" : [
{ id: "25160228446835585906563830293" ,
date: ISODate("2013-03-26T04:51:36.731Z") },
{ id: "25160228446835585906563830294" ,
date: ISODate("2013-03-26T04:51:36.731Z") },
{ id: "25160228446835585906563830295" ,
date: ISODate("2013-03-26T04:51:36.731Z") }
],
"users" : [
{ id: "25160228446835585906563830296",
date : ISODate("2013-03-26T04:51:36.731Z") }
]
}

If you are using mongodb java driver you can do the following:
BasicDBObject queryForAdminsID = new BasicDBObject("admins." + adminsID, new BasicDBObject("$exists", true));
// BasicDBObject queryForUsersID = new BasicDBObject("users." + usersID, new BasicDBObject("$exists", true));
cursor = coll.find(query); // coll is a DBCollection
try {
while(cursor.hasNext()) {
System.out.println(cursor.next());
}
} finally {
cursor.close();
}
where usersID and adminsID are your ids

Related

Getting the ArrayOfObjects value in MongoDb with java driver

I need to compare the requestParam system and Email Systems system ,if both are equal ,result value should be feteched based that system
{
"_id" : ObjectId("5f0890e870e631865877e"),
"user" : "testuser",
"Email" : "testuser#sample.com",
"Batch Systems" : [
"STAR",
"STORY",
"ITEMS",
],
"Email Systems" : [
{
"Bob" : {
"System" : "Bob",
**"result"** : true
}
},
{
"Wild" : {
"System" : "Wild",
"result" : true
}
},
{
"CRaft" : {
"System" : "Craft",
"result" : false
}
}
]
}
public Object getDetails(#RequestParam(value = "system") String userId,
MongoDatabase database = this.mongoClient.getDatabase(this.database);
MongoCollection<Document> users = database.getCollection(users);
String searchString = new String(sourceSystem);
Document matchDoc = new Document("$Email Systems.Bob.System",searchString);
Document projectDoc = new Document("$Email Systems","EmailSystem");
AggregateIterable<Document> aggregateIterable = users.aggregate(Arrays.asList( new Document("$match", matchDoc)));
Iterator iterator = aggregateIterable.iterator();
ArrayList<Document> documents = new ArrayList();
while (iterator.hasNext()) {
boolean doc = documents.add((Document) iterator.next());
About Code is giving results [Document{{Bob=Document{{System=Bob, result=true}}}}, Document{{Wild=Document{{System=Wild, result=true}}}}]
I am not able to get the Bob result value and it should be compared with the request param system .Can anyone help me the way to get the Bob result value based on above output

Mongo DB UpdateOne with c#

I've got this data in mongodb
{"_id" : "pippo",
"Rich" : [
{
"_id" : "8c9379f1-ba5a-4b43-b7ad-f5fe3bf6f09d",
"Appr" : null
},
{
"_id" : "8c9379f1-265a-4b43-b7ad-f5fe3bf6f09d",
"Appr" : null
}
]},
{"_id" : "pluto",
"Rich" : [
{
"_id" : "8c9379f1-ba5a-4b43-b7ad-f5fe3bf6f09d",
"Appr" : null
},
{
"_id" : "8c9379f1-265a-4b43-b7ad-f5fe3bf6f09d",
"Appr" : null
}
]},
How can i update, with the command UpdateOne, in document "Pippo" the property "Appr" inside the array "Rich" having "_id" 8c9379f1-265a-4b43-b7ad-f5fe3bf6f09d?
thank you
Bruno
UPDATE
I try this
var filter = Builders<RichiestaGiornalieri>.Filter.Eq("id", Pippo);
var update = Builders<RichiestaGiornalieri>.Update.Set("rich.appr", new[] { new Approvazione() { Approvata = true",
Approvatore = User.Identity.Name,
DataApprovazione = DateTime.Now,
id = Guid.NewGuid().ToString(),
Note = "" }
});
var arrayFilters = new List<ArrayFilterDefinition> { new JsonArrayFilterDefinition<RichiestaGiornalieri>("{'rich.id':'8c9379f1-265a-4b43-b7ad-f5fe3bf6f09d'}") };
var updateOptions = new UpdateOptions { ArrayFilters = arrayFilters };
dbRichieste.UpdateOne(filter, update, updateOptions);
But i receive this error messagge
MongoBulkWriteException`1: A bulk write operation resulted in one or more errors.
The array filter for identifier 'rich' was not used in the update { $set: { rich.appr: [ { DataApprovazione: new Date(1599579246919), _id: "2a5cc55e-70e8-4138-ace2-6b5131cd4a9a", Approvata: true, Approvatore: "Pippo", Note: "" } ] } }

grouping mongo documents using elements of array field

I have below 3 documents. Each represents a contact for a user :
{
"_id" : ObjectId("57f9f9f3b91d070315273d0d"),
"profileId" : "test",
"displayName" : "duplicateTest",
"email" : [
{
"emailId" : "a#a.com"
},
{
"emailId" : "b#b.com"
},
{
"emailId" : "c#c.com"
}
]
}
{
"_id" : ObjectId("57f9fab2b91d070315273d11"),
"profileId" : "test",
"displayName" : "duplicateTest2",
"email" : [
{
"emailId" : "a#a.com"
}
]
}
{
"_id" : ObjectId("57f9fcefb91d070315273d15"),
"profileId" : "test",
"displayName" : "duplicateTest2",
"email" : [
{
"emailId" : "b#b.com"
}
]
}
I need to aggregate/group them by array elements so that I can identify the duplicate contact ( based on email id). Since there is a common email id between doc (1 & 2) and doc( 1 & 3) these 3 represent one contact and should be merged into one as one contact.
I tried doing this using $unwind and $group in java as below:
List<DBObject> aggList = new ArrayList<DBObject>();
BasicDBObject dbo = new BasicDBObject("$match", new BasicDBObject("profileId", "0fb72dcf-292b-4343-a0e7-1d613a803b1e"));
aggList.add(dbo);
BasicDBObject dboUnwind = new BasicDBObject("$unwind", "$email");
aggList.add(dboUnwind);
BasicDBObject dboGroup = new BasicDBObject("$group",
new BasicDBObject().append("_id", new BasicDBObject("name", "$email.emailId"))
.append("uniqueIds", new BasicDBObject("$addToSet", "$_id"))
.append("count", new BasicDBObject("$sum", 1)));
aggList.add(dboGroup);
BasicDBObject dboCount = new BasicDBObject("$match", new BasicDBObject("count", new BasicDBObject("$gte", 2)));
aggList.add(dboCount);
BasicDBObject dboSort = new BasicDBObject("$sort", new BasicDBObject("count",-1));
aggList.add(dboSort);
BasicDBObject dboLimit = new BasicDBObject("$limit", 10);
aggList.add(dboLimit);
AggregationOutput output = collection.aggregate(aggList);
System.out.println(output.results());
This groups docs by email id (and rightly so) but doesn't serves the purpose.
Any help would be highly appreciated.
I need to implement the feature where user can be prompted about the possible duplicate contacts in his repository. I need aggregation result to be something like:
[
{
"_id":{
"name":[
{
"emailId" : "a#a.com"
},
{
"emailId" : "b#b.com"
},
{
"emailId" : "c#c.com"
}
]
},
"uniqueIds":[
{
"$oid":"57f9fcefb91d070315273d15"
},
{
"$oid":"57f9fcefb91d070315273d11"
},
{
"$oid":"57f9fcefb91d070315273d15"
}
],
"count":3
},
So basically, I need _id for all possible duplicate contacts (there could be another group of duplicates with _ids list as above) so that I can prompt it to user and user can merge them at his will.
Hope its more clear now. Thanks!
Well your question differs a bit from the result you are seeking. Your inital question pointed me to the following aggregation:
db.table.aggregate(
[
{
$unwind: "$email"
},
{
$group: {
_id : "$email.emailId",
duplicates : { $addToSet : "$_id"}
}
}
]
);
This results in:
{
"_id" : "c#c.com",
"duplicates" : [
ObjectId("57f9f9f3b91d070315273d0d")
]
}
{
"_id" : "b#b.com",
"duplicates" : [
ObjectId("57f9fcefb91d070315273d15"),
ObjectId("57f9f9f3b91d070315273d0d")
]
}
{
"_id" : "a#a.com",
"duplicates" : [
ObjectId("57f9fab2b91d070315273d11"),
ObjectId("57f9f9f3b91d070315273d0d")
]
}
Grouped by EMail.
But the sample output you added to your question made this aggregation:
db.table.aggregate(
[
{
$unwind: "$email"
},
{
$group: {
_id : "$profileId",
emails : { $addToSet : "$email.emailId"},
duplicates : { $addToSet : "$_id"}
}
}
]
);
Which results in:
{
"_id" : "test",
"emails" : [
"c#c.com",
"b#b.com",
"a#a.com"
],
"duplicates" : [
ObjectId("57f9fcefb91d070315273d15"),
ObjectId("57f9fab2b91d070315273d11"),
ObjectId("57f9f9f3b91d070315273d0d")
]
}

Mongo nested query with keys

Need help on MongoDB nested query. Below is my mongo collection.
Preference collection
{
"_id" : "user123",
"preferences" : {
"product-1" : {
"frequency" : "Weekly",
"details" : {
"email" : {
"value" : "On"
}
}
},
"product-2" : {
"preferencesFor" : "mpc-other",
"preferencesForType" : "Product",
"details" : {
"email" : {
"value" : "Off"
}
}
},
"product-3" : {
"preferencesFor" : "mpc-other",
"preferencesForType" : "Product",
"details" : {
"email" : {
"value" : "On"
}
}
}
}
}
Product Collection
{
"_id" : "product-1",
"name" : "Geo-Magazine"
}
{
"_id" : "product-2",
"name" : "History-Magazine"
}
{
"_id" : "product-3",
"name" : "Science-Magazine"
}
product-1, product-2... are keys from a Map.
The keys are stored in another collection Product Collection.
Can I create a nested query to cross-reference the product keys from another table?
I need the output in the below table format. Please suggest.
user123 product-1 email On
user123 product-2 email Off
user123 product-3 email On
I tried the below but can't get result. Please suggest.
var cursor = db.productSummary.find();
while(cursor.hasNext()){
var sku = cursor.next()._id;
var skuCol = "preferences."+sku+".details.email";
var skuVal = "preferences."+sku+".details.email.value";
db.marketingPreferences.find( {}, {_id:1, skuCol:1, skuVal:1});
}
> var myCursor = db.productSummary.find();
> while(myCursor.hasNext()){
var sku = myCursor.next()._id;
var skuCol = "preferences."+sku+".details.email";
var skuVal = "$preferences."+sku+".details.email.value";
var result = db.marketingPreferences.aggregate([{"$project":{"_id":1,value:skuVal,preferences:{$literal: sku}}}],{allowDiskUse: true});
while(result.hasNext()){
printjson(result.next());
}
}
Result
{ "_id" : "user123", "preferences" : "product-1", "value" : "On" }
{ "_id" : "user123", "preferences" : "product-2", "value" : "Off" }
{ "_id" : "user123", "preferences" : "product-3", "value" : "On" }
There's a difference between MongoDB and normal SQL DB. Firstly, when you query a MongoDB collection, it doesn't return a row as it will in a SQL db. What you get here is a document similar to JSON.
Also when you use preferences.product-1.details.email : 1 it wont return you the word 'email', rather it will return you the value ie. {"value" : "On" }.
Using this: db.preference.find({},{"_id":1,"preferences.product1.details.email.value":1})
you will be able to get two details which are user123 and On and you can get product-1 from your previous query. You can store these values in a variable and keep printing them to obtain the table necessary. Also you would need another cursor to store the result of the second second query that you would do.
Here's what your query will produce if it was single standalone query:
> db.preference.find({},{"_id":1,"preferences.product1.details.email.value":1})
.pretty()
{
"_id": "user123",
"preferences": {
"product-1": {
"details": {
"email": {
"value": "On"
}
}
}
}
}
public static void test(){
MongoCollection<Document> collection = getDatadase().getCollection("product");
MongoCollection<Document> pref = getDatadase().getCollection("pref");
List<Document> allDocList = collection.find().into(new ArrayList<Document>());
for(Document doc:allDocList){
System.out.println(doc.get("_id"));
String preferences = doc.get("_id")+"";
String sku = "$preferences."+preferences+".details.email.value";
Document aggregation = new Document().append("$project", new Document().append("_id", 1).append("value", sku));
List<Document> pipeline = new ArrayList<Document>();
pipeline.add(aggregation);
List<Document> aggList = pref.aggregate(pipeline).into(new ArrayList<Document>());
for(Document doc1:aggList){
System.out.println(doc1.append("preferences", preferences));
}
}
}
This Will return
product-1
Document{{_id=user123, value=On, preferences=product-1}}
product-2
Document{{_id=user123, value=Off, preferences=product-2}}
product-3
Document{{_id=user123, value=On, preferences=product-3}}

MongoDb: Aggregation using Groovy language

Iam using groovy scripting under SpagoBI. I want to use aggregation.
I want for example to execute the following aggregation:
db.myCollection.aggregate(
[
{
$group : {
_id : { day: { $dayOfMonth: "$recvTime" } }
}
}
]
)
I tried:
DBObject projectFields = new BasicDBObject('$dayOfMonth',"recvTime");
DBObject project=new BasicDBObject('$project',projectFields)
DBObject groupFields = new BasicDBObject( "_id",project);
DBObject group = new BasicDBObject('$group', groupFields);
iterable = db.getCollection('myCollection').aggregate(group)
I got this error:
An unexpected error occured while executing dataset: { "serverUsed" : "192.168.1.160:27017" , "errmsg" : "exception: invalid operator '$project'" , "code" : 15999 , "ok" : 0.0}
Any ideas?
Updates:
the query executed in Mongo shell
db['cygnus_/kurapath_enocean_power_enocean'].aggregate(
... [
... {
... $group : {
... _id : { day: { $dayOfMonth: "$recvTime" } }
... }
... }
... ]
... );
{ "_id" : { "day" : 9 } }
{ "_id" : { "day" : 8 } }
{ "_id" : { "day" : 7 } }
{ "_id" : { "day" : 4 } }
{ "_id" : { "day" : 3 } }
the data stored in mongo db:
db['cygnus_/kurapath_enocean_power_enocean'].find()
{ "_id" : ObjectId("55e81e9631d7791085668331"), "recvTime" : ISODate("2015-09-03T10:19:02Z"), "attrName" : "power", "attrType" : "string", "attrValue" : "2085.0" }
{ "_id" : ObjectId("55e81e9631d7791085668332"), "recvTime" : ISODate("2015-09-03T10:19:02Z"), "attrName" : "power", "attrType" : "string", "attrValue" : "2085.0" }
{ "_id" : ObjectId("55e81e9831d7791085668333"), "recvTime" : ISODate("2015-09-03T10:19:04Z"), "attrName" : "power", "attrType" : "string", "attrValue" : "2077.0" }
From the error, the aggregation is not expecting the $project operator so you should change the projectFields and project variables to show the actual pipeline expressions i.e.
DBObject dateFields = new BasicDBObject("$dayOfMonth", "$recvTime");
DBObject dateObject = new BasicDBObject("day", dateFields);
DBObject groupFields = new BasicDBObject( "_id", dateObject);
DBObject group = new BasicDBObject('$group', groupFields);
iterable = db.getCollection('myCollection').aggregate(group);
In SpagoBI you have 2 ways to create a dataset of type MongoDB:
1) use a dataset of type Query and use JS language
2) use a dataset of type java class and write your code in java
For solution 1 you should create a dataset of type query, select a datasource MongoDB and write on the field QUERY the query in js following the specification written here (http://wiki.spagobi.org/xwiki/bin/view/spagobi_server/data_set#HQueryDataSet28Mongo29)
The button “Edit script” is used to modify the query string and you can find some tip in the wiki. So if the query is SQL you can use a js o groovy script to change the query string (for example apply some logic to create parameters or table names)
You can express your query in this way:
Var query = db.myCollection.aggregate(
[
{
$group : {
_id : { day: { $dayOfMonth: "$recvTime" } }
}
}
]
)