How to aggregate values in an array of objects in MongoDB - mongodb

I store documents from cars and want to get the temperature of all Mercedes cars as an array, how should the query be in Mongodb?
{ "_id" : { "$oid" : "5880ff305d15f416c89457b7" },
"car" : "mercedes",
"engine" : {
"sensor" : {
"temperatur" : "20",
"speed" : "100",
"hue" : "40"
}
},
"motor" : {
"Power" : "155",
"Topspeed" : "400"
}
}
{ "_id" : { "$oid" : "5880ff305d15f416c89457b7" },
"car" : "mercedes",
"engine" : {
"sensor" : {
"temperatur" : "50",
"speed" : "100",
"hue" : "40"
}
},
"motor" : {
"Power" : "155",
"Topspeed" : "400"
}
}
I would like to select the temperature for all Mercedes cars and receive it.
result should be like [20,50]
EDIT:
My code lookls like the following iam using JAVA:
MongoClient mongoClient = new MongoClient();
MongoDatabase database = mongoClient.getDatabase("test");
MongoCollection<Document> coll = database.getCollection("myTestCollection");

You can try something like this with regular query if you're okay with distinct values.
db.cars.distinct("engine.sensor.temperatur", {"car" : "mercedes"});
This will give you
[ "20", "50" ]
Update - Java equivalent:
List<String> temps = coll.distinct("engine.sensor.temperatur", new Document("car", "mercedes"), String.class).into(new ArrayList<>());
Update - Aggregation Option
Bson match = new Document("$match", new Document("car", "mercedes"));
Bson group = new Document("$group", new Document("_id", "$car").append("temps", new Document("$push", "$engine.sensor.temperatur")));
List<String> temps = (List<String>) coll.aggregate(Arrays.asList(match, group)).map(document -> document.get("temps")).first();

Related

MongoDB delete specific nested element in object array

I want to remove this
"lightControl" : 75
from this
{
"_id" : "dfdfwef-fdfd-fd94284o-aafg",
"name" : "Testing",
"serialNumber" : "fhidfhd8ghfd",
"description" : "",
"point" : {
"type" : "Point",
"coordinates" : [
10.875447277532754,
20.940549069378634
]
},
"ancestors" : [ ],
"metadata" : {
"measurement" : {
"high" : "40000.0",
"medium" : "25000.0"
},
"digitalTwin" : {
},
"emails" : [
""
],
"lastMeasurementDate" : "2010-03-04T11:32:06.691Z",
"lightControl" : 75
},
"tags" : [ ],
"createdAt" : ISODate("2019-12-07T15:22:10.988Z"),
"updatedAt" : ISODate("2020-03-08T15:38:21.736Z"),
"_class" : "com.test.demo.api.model.Device"
}
All I want is for this specific id, to completely delete the lightControl element from metadata. I have tried $pull, but I am probably missing something. Any ideas? Thank you in advance!
Your lightControl is not in array, for nested property, use the dot wrapped in doublequotes:
MongoDB shell:
db.getCollection('yourCollectionName').update({},{$unset:{
"metadata.lightControl":""
}})
In case you have a list of objects with _id(s) instead of updating directly, assume Node.js client for MongoDB is used:
// import mongodb from "mongodb"; // ES6
const mongodb = require("mongodb");
var client = MongoClient(...);
var coll = client["yourDbName"]["yourCollectionName"];
var objs = []; // <-- The array with _id(s)
for (let i=0; i<objs.length; i++){
let id = mongodb.ObjectID(objs[i]["_id"]);
coll.update({ _id:id },{$unset:{ "metadata.lightControl":"" }});
}

how to copy document and create new document with new filed value in mongodb

I want to find one document and clone/copy that document and create 100 new documents with new value for few fields using shell script in mongodb.
Below is my document
{
"_id" : ObjectId("5ef59bde562c9824176e9f20"),
"productDefinition" : {
"product" : {
"companies" : {
"company" : {
"productionformation" : {
"productNumber" : "E128",
"venderNumber" : "0470",
"venderName" : "ALPHA SERVICES LLC"
}
}
}
}
},
"executionId" : "123456"
}
After executing the shell script, i want to have new 100 collection with new values for the below fields
"executionId" : "NewExecutionId" // This value will be Fixed for all new 100 documents
"productNumber" : "1" //This value will be increasing.. for first document 1, for second document 2, etc..
"venderNumber" : "1" //This value will be increasing.. for first document 1, for second document 2, etc..
My new collection will be looking like this.
First new document
{
"_id" : ObjectId("5ef59bde562c9824176e9f20"),
"productDefinition" : {
"product" : {
"companies" : {
"company" : {
"productionformation" : {
"productNumber" : "1",
"venderNumber" : "1",
"venderName" : "ALPHA SERVICES LLC"
}
}
}
}
},
"executionId" : "newExecutionId"
}
Second new document
{
"_id" : ObjectId("5ef59bde562c9824176e9f20"),
"productDefinition" : {
"product" : {
"companies" : {
"company" : {
"productionformation" : {
"productNumber" : "2",
"venderNumber" : "2",
"venderName" : "ALPHA SERVICES LLC"
}
}
}
}
},
"executionId" : "newExecutionId"
}
Third new document
{
"_id" : ObjectId("5ef59bde562c9824176e9f20"),
"productDefinition" : {
"product" : {
"companies" : {
"company" : {
"productionformation" : {
"productNumber" : "3",
"venderNumber" : "3",
"venderName" : "ALPHA SERVICES LLC"
}
}
}
}
},
"executionId" : "newExecutionId"
}
Like this fourth document , fifth document, etc... till 100th document...
I tried with this script. but its not working.
copy = db.myCollection.find({"executionId" : "123456",
"productDefinition.product.companies.company.productionformation.productNumber" : "E128" ,
"productDefinition.product.companies.company.productionformation.venderNumber" :"0470" })
for (var i = 1; i< 101; i++){
copy.executionId = "newExecutionId";
copy.productDefinition.product.companies.company.productionformation.productNumber = i;
copy.productDefinition.product.companies.company.productionformation.venderNumber" = i;
db.myCollection.insert(copy);
}
You will be needing to fix following things:
Use findOne instead of find as it will return single matching document.
Use let (instead of var) while running the loop because there are asynchronous DB operations in loop body.
Similarly, create a Deep copy of matchedDoc result / (copy variable) inside for loop body, to avoid updating same object's reference value.
Hope it helps !

Spring data mongodb - MappedResults returns blank list

Mongodb query is:
db.getCollection('country2').aggregate([{"$lookup":{"from":"state2","localFiel
d":"_id","foreignField":"countryId","as":"state2"}}]).pretty()
returns this result :
{
"_id" : ObjectId("5b2b520333a04107677b5ce1"),
"countryName" : "India",
"state2" : [
{
"_id" : ObjectId("5b2b515b33a04107677b5cdb"),
"stateName" : "UP",
"countryId" : ObjectId("5b2b520333a04107677b5ce1")
},
{
"_id" : ObjectId("5b2b516033a04107677b5cdc"),
"stateName" : "MP",
"countryId" : ObjectId("5b2b520333a04107677b5ce1")
}
]
}
Aggregation query returns blank MappedResults though raw results contain the expected results.
State2 is my java pojo.
public List<BasicDBObject> getAllData() {
LookupOperation lookUpOprn = LookupOperation.newLookup()
.from("state2")
.localField("_id")
.foreignField("countryId")
.as("state2");
org.springframework.data.mongodb.core.aggregation.AggregationOptions options = Aggregation.newAggregationOptions().cursor(new BasicDBObject()).build();
Aggregation aggregation = Aggregation.newAggregation(lookUpOprn).withOptions(options);
List<BasicDBObject> list = mongoOperations.aggregate(aggregation, "country2", BasicDBObject.class).getMappedResults();
return list;
}
Can you please help.

Spring data and mongoDB - aggregation with java list

I have the following document (#Document):
#Id
private String id;
private String fileName;
private String projectId;
private List<DocumentFileVersion> documentFileVersions;
private List<String> userIdBlackList; // here userIds are included
and this is my current aggregation:
final String userId = "5589929b887dc1fdb501cdbb";
final Aggregation aggregate = newAggregation(match(Criteria.where("projectId").in(projectId)),
group("fileName").count().as("amountOfDocumentFiles"));
final AggregationResults<DocumentFileAmount> groupDocumentFiles = mongoTemplate.aggregate(aggregate, DocumentFile.class,
DocumentFileAmount.class);
final List<DocumentFileAmount> documentFileAmounts = groupDocumentFiles.getMappedResults();
final int amountOfDocumentFiles = documentFileAmounts.size();
Now I will extend the aggreagation in that way that I only will have the DocumentFiles where userId (in this case "1234") is not in userIdBlackList.
Is there a possibility to do that, like in pseudocode:
final Aggregation aggregate = newAggregation(match(Criteria.where("projectId").in(projectId).and(userId).notInList("userIdBlackList")),
group("fileName").count().as("amountOfDocumentFiles"));
I would need something like this: ... .and(userId).notInList("userIdBlackList") ...
[EDIT]
I have tried this query:
final Aggregation aggregate = newAggregation(
match(Criteria.where("projectId").in(projectId).and(userId).and("‌​userIdBlackList").ne(userId)),
group("fileName").count().as("amountOfDocumentFiles"));
A Database entry can look like this:
{
"_id" : ObjectId("587e7cabafdaff28743f3034"),
"_class" : "com.smartinnotec.legalprojectmanagement.dao.domain.DocumentFile",
"fileName" : "Hydrangeas.jpg",
"projectId" : "587e7c95afdaff28743f302e",
"userIdBlackList" : [
"5589929b887dc1fdb501cdbb"
]
}
but .and(userId).and("‌​userIdBlackList").ne(userId) has no effect.
[EDIT2]
I have tried to simulate it in the mongo console too.
I have listed all documentfiles with the command db.DocumentFile.find().pretty():
db.DocumentFile.find().pretty()
{
"_id" : ObjectId("587f0d61473c92b933a68efa"),
"_class" : "com.smartinnotec.legalprojectmanagement.dao.domain.DocumentFile",
"fileName" : "DocumentFile1",
"ending" : "jpg",
"projectId" : "587f0d61473c92b933a68ef9",
"active" : true,
"userIdBlackList" : [
"587f0d61473c92b933a68ef8"
]}
and my query looks like this:
db.DocumentFile.aggregate({ "$match" : { "projectId" : { "$in" : [ "587f0d61473c92b933a68ef9"]} , "‌​userIdBlackList" : { "$ne" : "587f0d61473c92b933a68ef8"}}}).pretty();
{
"_id" : ObjectId("587f0d61473c92b933a68efa"),
"_class" : "com.smartinnotec.legalprojectmanagement.dao.domain.DocumentFile",
"fileName" : "DocumentFile1",
"ending" : "jpg",
"projectId" : "587f0d61473c92b933a68ef9",
"active" : true,
"userIdBlackList" : [
"587f0d61473c92b933a68ef8"
]}
I have expected that I do not get a documentfile because of this expression "‌​userIdBlackList" : { "$ne" : "587f0d61473c92b933a68ef8"}
Does anyone know what I am doing wrong?
[EDIT3]
I have this two documents and with the aggegate:
final Aggregation aggregate = newAggregation(
match(Criteria.where("projectId").in(projectId).and("‌​userIdBlackList").nin(userId)),
group("fileName").count().as("amountOfDocumentFiles"));
I get the amount of 2 but it should 1. I don't know what I am doing wrong?
db.DocumentFile.find().pretty()
{
"_id" : ObjectId("587f2228e232342f74b166f9"),
"_class" : "com.smartinnotec.legalprojectmanagement.dao.domain.DocumentFile",
"fileName" : "DocumentFile1",
"ending" : "jpg",
"projectId" : "587f2228e232342f74b166f8",
"active" : true,
"userIdBlackList" : [
"587f2228e232342f74b166f7"
]}
{
"_id" : ObjectId("587f2228e232342f74b166fa"),
"_class" : "com.smartinnotec.legalprojectmanagement.dao.domain.DocumentFile",
"fileName" : "DocumentFile2",
"ending" : "jpg",
"projectId" : "587f2228e232342f74b166f8",
"active" : true,
"userIdBlackList" : [ ]
}
Have you tried using .nin
final Aggregation aggregate = newAggregation(
match(Criteria.where("projectId").in(projectId).and("‌​userIdBlackList").nin(userId)),
group("fileName").count().as("amountOfDocumentFiles"));

Spring data mongodb check inside array whether value presents

I want to fetch all documents in which readBy array has suppose "2" value using spring data API.
Please help me.
My JSON in Mongodb is like this.
{
"_id" : ObjectId("52c14eb92f7ceb854e445354"),
"attachments" : [{
"fileMongoId" : "52c14eb82f7ceb854e44534b",
"fileName" : "Desert.jpg",
"fileSize" : "0 MB",
"fileType" : "image/jpeg"
}, {
"fileMongoId" : "52c14eb82f7ceb854e445350",
"fileName" : "Hydrangeas.jpg",
"fileSize" : "0 MB",
"fileType" : "image/jpeg"
}],
"from" : NumberLong(2),
"fromName" : "xyz",
"hasAttachment" : true,
"message" : "Hi all\r\n",
"read" : 1,
"readBy" : ["2", "3"],
"sentTime" : NumberLong("1388400312645"),
"sentType" : 2,
"subject" : "Hi",
"to" : [{
"toId" : "3",
"toName" : "pqr"
}, {
"toId" : "2",
"toName" : "xyz"
}]
}
Code to generate query
Username is string which I want to check whether it is present in readBy array or not
readBy is array of String
Query query = new Query();
Update update = new Update();
Criteria criteria = new Criteria();
if (read) {
// criteria = Criteria.where(username).in("readBy");
query.addCriteria(criteria.andOperator(Criteria.where("to.toId")
.in(toIdList)));
} else {
// criteria = Criteria.where(username).nin("readBy");
update.addToSet("readBy", username);
query.addCriteria(criteria.andOperator(Criteria.where("to.toId")
.in(toIdList)));
mongoTemplate.updateMulti(query, update, NewMessage.class);
}
query.fields().include("from");
query.fields().include("fromName");
query.fields().include("sentTime");
query.fields().include("hasAttachment");
query.sort().on("sentTime", Order.DESCENDING);
newMessages = mongoTemplate.find(query, NewMessage.class);