I'm trying to convert this javascript code into java code to be used in Spring Data:
proj3={"$project": {
"comms" : 1,
"same" : { "$eq" : ["$comms.i" , "$max"]},
"max" : 1,
"_id" : 1
}
};
I cannot seem to figure it out.
I have tried this:
BasicDBObject o3 = new BasicDBObject();
o3.append("$eq", "[\"$comms.i\",\"$max\"]");
Aggregation aggCount2 = newAggregation(project("comms", "max", "_id").andExpression("same", o3));
logger.info(aggCount2.toString());
This is what is logged:
{ "$project" : { "comms" : 1 , "max" : 1 , "_id" : 1}}
I also read this thread: Spring Data MongoDB - $eq within $project support but the poster seemed to have given up and used the executeCommand option instead which is not the route I would like to go.
How can I get this code to work in java Spring Data Mongodb?
This is how I solved it, it might not be the most efficient way but it seem to work without too much code rewrite.
First, I looked at the answer in this thread:
Aggregation Project Group By extracted day, month and year with Spring Data
Blakes Seven proposed that I use a special custom aggregationOperation class so that the aggregation code will take BasicDBObjects:
public class CustomGroupOperation implements AggregationOperation {
private DBObject operation;
public CustomGroupOperation (DBObject operation) {
this.operation = operation;
}
#Override
public DBObject toDBObject(AggregationOperationContext context) {
return context.getMappedObject(operation);
}
}
Next, you just format the project code you want into the BasicDBObject:
BasicDBList basicDBList = new BasicDBList();
basicDBList.add("$comms.i");
basicDBList.add("$max");
Aggregation aggCount2 = newAggregation(
match(),
project(),
group(),
new CustomGroupOperation(new BasicDBObject("$project",
new BasicDBObject("comms", 1)
.append("max", 1)
.append("_id", 1)
.append("same", new BasicDBObject("$eq", basicDBList)))),
match(),
project(),
group(),
sort());
Print it out in the logger and you will see that the format for the javascript code is now correct.
{ "$project" : { "comms" : 1 , "max" : 1 , "_id" : 1 , "same" : { "$eq" : [ "$comms.i" , "$max"]}}}
Related
Mongo document:
{
"_id" : "1",
"array" : [
{
"item" : "item"
},
{
"item" : "item"
}
]
}
My mongo shell query looks like so:
db.getCollection('collectionName').aggregate(
{$match: { _id: "1"}},
{$project: { count: { $size:"$array" }}}
)
Is there anyway to implement this using the Mongo Template from Spring?
So far I have this:
MatchOperation match = new MatchOperation(Criteria.where("_id").is("1"));
ProjectionOperation project = new ProjectionOperation();
Aggregation aggregate = Aggregation.newAggregation(match, project);
mongoTemplate.aggregate(aggregate, collectionName, Integer.class);
I think I am only missing the project logic but I'm not sure if it is possible to do $size or equivalent here.
It's quite possible, the $size operator is supported (see DATAMONGO-979 and its implementation here). Your implementation could follow this example:
import static org.springframework.data.mongodb.core.aggregation.Aggregation.*;
Aggregation agg = new Aggregation(
match(where("_id").is("1")), //
project() //
.and("array") //
.size() //
.as("count")
);
AggregationResults<IntegerCount> results = mongoTemplate.aggregate(
agg, collectionName, Integer.class
);
List<IntegerCount> intCount = results.getMappedResults();
Please find below the sample code. You can change it accordingly for your requirement with collection name, collection name class and array field name.
MatchOperation match = new MatchOperation(Criteria.where("_id").is("1"));
Aggregation aggregate = Aggregation.newAggregation(match, Aggregation.project().and("array").project("size").as("count"));
AggregationResults<CollectionNameClass> aggregateResult = mongoOperations.aggregate(aggregate, "collectionName", <CollectionNameClass>.class);
if (aggregateResult!=null) {
//You can find the "count" as an attrribute inside "result" key
System.out.println("Output ====>" + aggregateResult.getRawResults().get("result"));
System.out.println("Output ====>" + aggregateResult.getRawResults().toMap());
}
Sample output:-
Output ====>[ { "_id" : "3ea8e671-1e64-4cde-bd78-5980049a772b" , "count" : 47}]
Output ====>{serverUsed=127.0.0.1:27017, waitedMS=0, result=[ { "_id" : "3ea8e671-1e64-4cde-bd78-5980049a772b" , "count" : 47}], ok=1.0}
You can write query as
Aggregation aggregate = Aggregation.newAggregation(Aggregation.match(Criteria.where("_id").is(1)),
Aggregation.project().and("array").size().as("count")); mongoTemplate.aggregate(aggregate, collectionName, Integer.class);
It will execute the following query { "aggregate" : "collectionName" , "pipeline" : [ { "$match" : { "_id" : 1}} , { "$project" : { "count" : { "$size" : [ "$array"]}}}]}
I have aggregation that works in mongo and i need to create the exact one in java with spring. I didn't find a way. Do you know if there is one?
db.collection_name.aggregate([
{
$group: {
_id : {
year : {$year : "$receivedDate" },
month : {$month: "$receivedDate"},
day : { $dayOfMonth : "$receivedDate"}
},
count : { $sum: 1 }
}
}
])
You could try projecting the fields first by using the SpEL andExpression in the projection operation and then group by the new fields in the group operation:
Aggregation agg = newAggregation(
project()
.andExpression("year(receivedDate)").as("year")
.andExpression("month(receivedDate)").as("month")
.andExpression("dayOfMonth(receivedDate)").as("day"),
group(fields().and("year").and("month").and("day"))
.count().as("count")
);
I'm making a MongoDB statistic system using the Java driver, and I am wondering if it is possible (and how) to change the value of a key nested inside many objects. Here is how my database is formatted:
{
location : “chicago”,
stats : [
{
"employee" : "rob",
"stat1" : 1,
"stat2" : 3,
"stat3" : 2
},
{
"employee" : "krista",
"stat1" : 1,
"stat2" : 3,
"stat3" : 2
}
]
}
So, for example, how could I change Rob's "stat2" to another value? I am new to JSON and the MongoDB Java driver. Any help is appreciated!
You need to use the positional $ operator and $set in order to update what you want.
db.collection.update(
{ _id: <docId>, "stats.employee": "rob" },
{ "$set": { "stats.$.stat2": <value> } }
)
So you match your document and the required element of the array. The update side uses that array index to know in which element to update. The $set operator only updates the specified field.
In Java, Build with BasicDBObject.
BasicDBObject query = new BasicDBObject("_id", id);
query.append( new BasicDBObject("stats.employee", "rob") );
BasicDBObject update = new BasicDBObject("$set",
new BasicDBObject("stats.$.stat2", value));
collection.update(query,update);
I am new to mongodb. Plz help me with this.
I need a document like this
employee{
_id:111,
name:xxx,
dependents : [ {
name:a,
age:51,
dep_children:[{name:aa}{name:bb}{name:c}]
}
{
name:b,
age:52,
dep_children:[{name:aa}{name:bb}{name:c}]
}
{
name:c,
age:51,
dep_children:[{name:aa}{name:bb}{name:cc}]
}
]
}
I am using the below script to migrate data for SQL and update it into mongoDB
My code looks something like this:
while(personcount>=0)
{
BasicDBObject doc = new BasicDBObject("_id",ind1.get(count)).
append("name",ind2.get(count));
coll.insert(doc);
while(dependentcount>0)
{
BasicDBObject querymongo = new BasicDBObject();
querymongo.put( "name",ind.get(count));
BasicDBObject tenant = new BasicDBObject();
tenant.put("name",indsa.get(innercount) );
tenant.put("age", indsa2.get(innercount));
BasicDBObject update = new BasicDBObject();
update.put("$push", new BasicDBObject("dependents",tenant));
coll.update(querymongo, update,true,true);
while(kidcount>0)
{
BasicDBObject querymongofact = new BasicDBObject();
querymongokid.put( "dependent.name",indsa.get(innercount));
BasicDBObject tenantkid = new BasicDBObject();
tenantkid .put("name",indfact.get(innercountfact) );
BasicDBObject updatekid = new BasicDBObject();
updatekid .put("$push", new BasicDBObject("dependent.dep_children",tenantkid));
coll.update(querymongokid, updatekid ,true,true);
}
}
}
when we print querymongokid and updatekid, the data inside it are expected values itself. This code is not throwing any error. But in data base the only dep_children data is not getting updated . I am not getting wt went wrong. please help me
Thanks in advance
Your last query fails in the mongo driver in a sense that the update has no effect - but it's not an actual error. Just let me reproduce what you are doing in the mongo shell:
> db.coll.insert({_id:1,name:"name1"})
> db.coll.update({name:"name1"}, {"$push": {dependents: {name:"a", age:50}}})
> db.coll.update({name:"name1"}, {"$push": {dependents: {name:"b", age:55}}})
> db.coll.findOne()
{
"_id" : 1,
"dependents" : [
{
"name" : "a",
"age" : 50
},
{
"name" : "b",
"age" : 55
}
],
"name" : "name1"
}
> db.coll.update({"dependents.name": "a"}, {"$push": {"dependents.dep_children": {name:"aa"}}})
can't append to array using string field name: dep_children
> db.coll.update({"dependents.name": "a"}, {"$push": {"dependents.$.dep_children": {name:"aa"}}})
> db.coll.findOne()
{
"_id" : 1,
"dependents" : [
{
"age" : 50,
"dep_children" : [
{
"name" : "aa"
}
],
"name" : "a"
},
{
"name" : "b",
"age" : 55
}
],
"name" : "name1"
}
Unfortunately, I have very little experience with the native mongo java driver (I'm usually on Spring data), but changing your line
updatekid.put("$push", new BasicDBObject("dependent.dep_children",tenantkid));
to
updatekid.put("$push", new BasicDBObject("dependent.$.dep_children",tenantkid));
should do the trick as well.
The reason for that behavior is that "dependent.dep_children" is not a valid selector as it corresponds to "go to field dep_children within the subdocument dependent". However, "dependent" happens to be an array without any fields. The $ replaces an explicit index and will make sure the correct subdocument from your query is selected.
Also see here for a less error-prone formulation of your query - without using $elemMatch it will only work if your query uniquely identifies a certain array element. With $elemMatch it will always work, but only update the first match.
I am very new to MongoDB and its Java... SDK? Api? I have a very simple question, but I haven't been able to find a satisfactory answer.
Let's say I have a collection of instances that are like:
{
"_id": {
"$oid": "5156171e5d451c136236e738"
},
"_types": [
"Sample"
],
"last_z": {
"$date": "2012-12-30T09:12:12.250Z"
},
"last": {
"$date": "2012-12-30T04:12:12.250Z"
},
"section": "5156171e5d451c136236e70f",
"s_mac": "AA:AA:AA:AA:AA:AA",
"_cls": "Sample",
}
And I have a hard-coded Java list:
static List<String> MAC_LIST = Arrays.asList("90:27:E4:0E:3D:D2", "A8:26:D9:E6:1D:8B");
What I would like to know is how to query the MongoDB so it will give me all the objects whose s_mac field has a value that appears in the MAC_LIST List.
I'm guessing I should use the $in operator, but I don't know how to translate it to Java code.
Any hint or link to pages with explanations of the use of the $in operator through the Java SDK would be appreciated!
Here is a contrived example that works for me (driver version 2.10.1) - you can adjust the IP address and run it as is to check if you get the same outcome:
public void gss() throws Exception{
MongoClient mongo = new MongoClient("192.168.1.1");
DB db = mongo.getDB("test");
DBCollection collection = db.getCollection("stackoverflow");
DBObject o1 = new BasicDBObject();
o1.put("s_mac", "AA:AA:AA:AA:AA:AA");
o1.put("_cls", "Sample1");
DBObject o2 = new BasicDBObject();
o2.put("s_mac", "90:27:E4:0E:3D:D2");
o2.put("_cls", "Sample2");
DBObject o3 = new BasicDBObject();
o3.put("s_mac", "A8:26:D9:E6:1D:8B");
o3.put("_cls", "Sample3");
collection.insert(o1, o2, o3);
System.out.println(collection.find().count());
List<String> MAC_LIST = Arrays.asList("90:27:E4:0E:3D:D2", "A8:26:D9:E6:1D:8B");
System.out.println(collection.find(new BasicDBObject("s_mac", new BasicDBObject("$in", MAC_LIST))).count());
}
It inserts the following documents:
{ "_id" : ObjectId("5159ff98567e143bff0668e9"),
"s_mac" : "AA:AA:AA:AA:AA:AA",
"_cls" : "Sample1"
}
{ "_id" : ObjectId("5159ff98567e143bff0668ea"),
"s_mac" : "90:27:E4:0E:3D:D2",
"_cls" : "Sample2"
}
{ "_id" : ObjectId("5159ff98567e143bff0668eb"),
"s_mac" : "A8:26:D9:E6:1D:8B",
"_cls" : "Sample3"
}
A call to collection.find().count() returns 3 and a call to collection.find(new BasicDBObject("s_mac", new BasicDBObject("$in", MAC_LIST))).count() returns 2 which I think is what you expected.