MongoDB Array modify Using Java - java

I am new to MongoDB, I want to remove an element from array structure as shown below:
{
"Data" : [
{
"url" : "www.adf.com"
"type":7
},
{
"url" : "www.pqr.com"
"type":2
}
{
"url" : "www.adf.com"
"type":3
},
{
"url" : "www.pqr.com"
"type":5
}
],
}
I want to remove url=www.adf.com which has type as lowest values i.e in this document my query should remove type=3 and return document as below:
{
"Data" : [
{
"url" : "www.adf.com"
"type":7
},
{
"url" : "www.pqr.com"
"type":2
}
{
"url" : "www.pqr.com"
"type":5
}
],
}

The query shown by #shakthydoss can be described in java as follows:
MongoClient mongoClient = new MongoClient("SERVER", 27017);
DB db = mongoClient.getDB("DB_NAME");
DBCollection coll1 = db.getCollection("COLLECTION_NAME");
DBObject eleMatch = new BasicDBObject();
eleMatch.put("url", "www.pqr.com");
eleMatch.put("type", new BasicDBObject("$lte", 50));
BasicDBObject up = new BasicDBObject();
up.put("$elemMatch", eleMatch);
BasicDBList basicDBList = new BasicDBList();
basicDBList.add(up);
DBObject query = new BasicDBObject("Data", new BasicDBObject(" $all", basicDBList));
coll1.find(query);

Use $all with $elemMatch
If the field contains an array of documents, you can use the $all with the $elemMatch operator.
db.inventory.find( {
Data: { $all: [
{ "$elemMatch" : { url : "www.pqr.com": "M", type: { $lte: 50} } },
] }
} )

Related

Update Mongo nested array using Java with multiple conditions

I have following document :
{
"_id" : ObjectId("5d42501efbf6f6108277ceb3"),
"customer" : {
"id" : "02c59458-8f0a-4a11-bff6-55b4710bc546",
"name" : "brookfield"
},
"userId" : "86c241de-16de-417d-8537-ed441fee9b0e",
"username" : "Fonville_f888f976_un_",
"userGroups" : [],
"lastSeen" : ISODate("2020-05-06T20:21:49.140Z"),
"devices" : [
{
"id" : "A920B6F24B63479B8796B709EA542951",
"displayId" : "A920B6F24B63479B8796B709EA542951",
"manufacturedId" : false,
"lastSeen" : ISODate("2020-03-20T14:36:24.961Z"),
"product" : {
"manufacturer" : "PSman",
"manufacturerCode" : 10,
"name" : "BlackHawk 880 series",
"modelId" : "C053"
}
},
{
"id" : "2476B0E045712cc-5904-11ea-af28-0612af3fc862",
"displayId" : "2476B0E16929512870992618563",
"lastSeen" : ISODate("2020-01-09T20:59:48.650Z"),
"product" : {
"manufacturer" : "GN",
"manufacturerCode" : 5,
"name" : "Telenor Speak 710",
"modelId" : "2476",
"vendorId" : "B0E"
}
}
],
"software" : {
"applicationId" : "f81d4fae-7dec-11d0-a765-00a0c91e6bf6",
"version" : "3.12.52334.30629",
"displayVersion" : "3.12.0"
},
"lastHost" : {
"name" : "hn_5934d3c5dbf",
"platform" : "WIN",
"osVersion" : "10.0.17763"
}
}
I have to update every product name inside devices array based on product modelId field.
So, user will pass two modelId values and if one of them match product's modelId than product name for that product should be updated.
I wrote following code, and I tested it with mongo db version 4.2, and it works. The problem is that when i tested it with older version of mongo db (3.4.23), it doesn't work,and I'm getting following exception :
com.mongodb.MongoCommandException: Command failed with error 9 (FailedToParse): 'Unrecognized field in update operation: arrayFilters' on server localhost:27017. The full response is { "ok" : 0.0, "errmsg" : "Unrecognized field in update operation: arrayFilters", "code" : 9, "codeName" : "FailedToParse" }
Here is how my method looks like :
private void updateCollection(String firstPid,String secondPid, String newProductName) {
MongoCollection<Document> collection = mongoTemplate.getCollection("user");
BasicDBObject searchQueryOne = new BasicDBObject();
BasicDBObject searchQueryTwo = new BasicDBObject();
BasicDBList or = new BasicDBList();
BasicDBObject query = new BasicDBObject("$or", or);
BasicDBObject updateQuery = new BasicDBObject();
searchQueryOne.append("devices.product.modelId", firstPid);
searchQueryTwo.append("devices.product.modelId", secondPid);
or.add(searchQueryOne);
or.add(searchQueryTwo);
updateQuery.append("$set",
new BasicDBObject().append("devices.$[elem].product.name", newProductName));
collection.updateMany(query, updateQuery, new UpdateOptions().arrayFilters(
Collections.singletonList( Filters.in("elem.product.modelId", Arrays.asList(firstPid,secondPid)))));
}
Please help
After some resarching, I managed to solve my problem. If someone have similar issue, here is the code that worked for me
public void updateUserCollection(String pidOne, String pidTwo) {
MongoCollection<Document> userCollection = mongoTemplate.getCollection("user");
BasicDBObject deviceCriteria = new BasicDBObject("devices.product.modelId", new BasicDBObject("$in", Arrays.asList(pidOne)));
FindIterable<Document> cursor = userCollection.find(deviceCriteria);
MongoCursor<Document> iterator = cursor.iterator();
while (iterator.hasNext()) {
Document user = iterator.next();
String userId = user.get("userId", String.class);
List<Document> devices = user.get("devices", List.class);
for (Document device : devices) {
Document product = device.get("product", Document.class);
String modelId = product.get("modelId", String.class);
if (modelId != null && (modelId.equals(pidOne) || modelId.equals(pidTwo))) {
product.put("name", newProductName);
}
}
saveUser(userId, user, userCollection);
}
iterator.close();
}
private void saveUser(String userId, Document user, MongoCollection<Document> userCollection) {
BasicDBObject updateQuery = new BasicDBObject("$set", user);
BasicDBObject searchQuery = new BasicDBObject("userId", userId);
userCollection.updateMany(searchQuery, updateQuery);
}

Need to update only particular element in an array of mongo in java

I want to update a particular element in an array of mongo with filters.
I have already tried having using BasicDBObject, but than not able to use filter as i have collection of type MongoCollection.
MongoCollection collection = db.getCollection(tnId);
Even tried:
FindIterable<Document> document = collection.find(new BasicDBObject("DocumentName", documentName) .append("Attributes.name", "Party 1" ).append("Attributes.value", 12) .append("Attributes.actualValue.initialValue", USA));
But in this case What I get is the whole record and than I have to iterate through each Attribute again.
mongo = new MongoClient("localhost", 27017);
MongoDatabase db = mongo.getDatabase(companyName);
MongoCollection collection = db.getCollection(tnId);
Actual data which I am passing is
{
"DocumentName" : "doc1",
"Attributes" : [
{
"name" : "Party 1",
"value" : 12,
"actualValue" : {
"initialValue" : "USA"
}
},
{
"name" : "Party 1",
"value" : 16,
"actualValue" : {
"initialValue" : "SYSTEM"
}
}
]
}
and I want to search attribute where actualValue is "USA" and Value of attribute is 12 and updated data should look like
{
"DocumentName" : "doc1",
"Attributes" : [
{
"name" : "Party 1",
"value" : 12,
"actualValue" : {
"initialValue" : "USA"
},
"updatedvalue" : {
"initialValue" : "USA",
"changedValue" : "Europe"
}
},
{
"name" : "Party 1",
"value" : 16,
"actualValue" : {
"initialValue" : "SYSTEM"
}
}
]
}
db.collection.findOneAndUpdate({ "Attributes.actualValue.initialValue": "USA" },
{ $set: { "Attributes.$.updatedvalue.initialValue": "USA", "Attributes.$.updatedvalue.changedValue": "Europe" } })
db.collection.findOneAndUpdate({ "Attributes.actualValue.initialValue": "USA" },
{ $set: { "Attributes.$.updatedvalue.initialValue": "India", "Attributes.$.updatedvalue.changedValue": "India" } })
Try with this one
db.collection.updateMany(
{ "Attributes.actualValue.initialValue": "USA" },
{ $set: { "Attributes.$.updatedvalue" : {
"initialValue" : "USA",
"changedValue" : "Europe"
} } }
)
How I did is. I made a document where i added teh required data which i want to update it with.Say
Document valueDocument = new Document();
valueDocument.put("InitialValue", USA);
BasicDBObject query = new BasicDBObject();
query.put("Attributes", att);
BasicDBObject data = new BasicDBObject();
data.put("Attributes.$.updatedvalue" + qCLevel, valueDocument);
BasicDBObject command = new BasicDBObject();
command.put("$set", data);
collection.updateOne(query, command);
It goes and insert the data in the right place.

Mongodb - update specific array element

I have a collection "prefs" with document structure as below
{
_id: {
userId: "abc"
},
val: {
status: 1,
prefs: [
{
value: "condition",
lastSent: ISODate("2017-07-17T23:46:53.717Z")
}
],
deal: 2,
prevDeal: 3
}
}
I am trying to update the date field lastSent with a condition on userId and status. Below are the queries that I derieved from my Java code.
Select Query:
{ "_id" : { "userId" : "abc"} , "val.status" : 1 , "val.prefs.value" : "condition"}
Update Query:
{ "$set" : { "val.prefs.$.lastSent" : { "$date" : "2017-07-17T23:50:07.009Z"}}}
The above query is giving error as follows:
The dotted field 'prefs.$.lastSent' in 'val.prefs.$.lastSent' is not valid for storage.
How do I achieve this?
Below is my Java code:
BasicDBObject _idObject = new BasicDBObject();
_idObject.put("userId", "abc");
BasicDBObject _selectQuery = new BasicDBObject();
_selectQuery.put("_id", _idObject);
_selectQuery.put("val.status", 1);
_selectQuery.put("val.prefs.value", "condition");
BasicDBObject _valueUpdateQuery = new BasicDBObject();
_valueUpdateQuery.put("prefs.$.lastSent", lastSent);
BasicDBObject _updateQuery = new BasicDBObject();
_updateQuery.put("$set", new BasicDBObject("val", _valueUpdateQuery));
prefs.update(_selectQuery, _updateQuery, true, true);
I just tested with your code in mongo shell this codes works fine you don't have to mention
$date
and i used this code for updating date
db.getCollection('tester').update({ "_id" : { "userId" : "abc"} , "val.status" : 1 , "val.prefs.value" : "condition"},{ "$set" : { "val.prefs.$.lastSent" : new Date()}})

Count document MongoDB java

I am new to MongoDB and I am finding rather complicated to count the child number of my nested documents.
This is part of my 'users' collection.
"_id" : ObjectId("58f9f7a91fb2bf7c46abe5d6"),
"name" : "fernando guima",
"premium" : true,
"email" : "lolol#loladamix.com",
"creationDate" : ISODate("2017-04-21T12:14:33.970Z"),
"playlists" : [
{
"name" : "minha Playlist",
"creationDate" : ISODate("2017-04-21T12:14:33.982Z"),
"videos" : [
{
"video_id" : "video1",
"creationDate" : ISODate("2017-04-21T13:00:38.461Z")
},
{
"video_id" : "video2",
"creationDate" : ISODate("2017-04-21T13:00:38.502Z")
}
]
},
{
"name" : "minha Playlist 2",
"creationDate" : ISODate("2017-04-21T12:14:33.983Z"),
"videos" : [ ]
}
]
}
I want to be able to retrieve the number of 'videos' in my 'playlist' (playlist childs) and retrieve a video data, how can I do that?
I wrote the following code that adds a video to a given playlist:
public void addToPlaylist(String parameter, String value, String playListName, String video_id){
//user document
BasicDBObject query = new BasicDBObject(parameter, value);
//First it fetches the wanted document by a parameter and its value e.g, (name, Fernando)
BasicDBObject mObject = new BasicDBObject();
mObject.put("video_id", video_id);
mObject.put("creationDate", new Date());
BasicDBObject updateObj = new BasicDBObject();
//falta percorrer o array das playlists para encontrar o id pelo nome da playlist
updateObj.put("$push", new BasicDBObject("playlists."+"0"+".videos", mObject));
mMongo.getCollection("users").updateOne(query, updateObj);
}
I expect to receive, {videos : 2} as the number of videos in my first playlist. And some output about video data like: {"video_id" : "video1"}
Regards
You can use below query. The query will $match to select the document followed by $unwind of playlists array and $project to reach videos array to calculate its $size and extract video_id.
MongoClient client = new MongoClient("localhost", 27017);
MongoDatabase database = client.getDatabase("db");
MongoCollection<Document> collection = database
.getCollection("collection");
Bson filter = Filters.eq("_id", new ObjectId("58f9f7a91fb2bf7c46abe5d6"));
List<VideoResult> results = collection.aggregate(Arrays.asList(Aggregates.match(filter), Aggregates.unwind("$playlists"), Aggregates.project(Projections.fields(Arrays.asList(Projections.computed("videos", new Document("$size","$playlists.videos")),
Projections.computed("video_ids", "$playlists.videos.video_id")))))).map(VideoResult::new).into(new ArrayList<>());
Output:
{
"_id" : ObjectId("58f9f7a91fb2bf7c46abe5d6"),
"videos" : 2,
"video_ids" : [
"video1",
"video2"
]
}
{
"_id" : ObjectId("58f9f7a91fb2bf7c46abe5d6"),
"videos" : 0,
"video_ids" : [ ]
}
Pojo:
public class VideoResult {
private int videos;
private List<String> videoIds;
public VideoResult(Document doc) {
this.videos = doc.getInteger("videos");
this.videoIds = (List<String>) doc.get("video_ids");
}
// getters and setters
}
Another solution, MongoDB 3.4
db.users.aggregate([
{$unwind: '$playlists'}, {$addFields: {'playlists.id': '$_id'}},
{$replaceRoot: {newRoot: '$playlists'}},
{$unwind: {path: '$videos', preserveNullAndEmptyArrays: true}},
{$group: {_id: {name: '$name', creationDate: '$creationDate', _id: '$id'},
video_ids: {$push: '$videos.video_id'},
videos: {$sum: {$cond: [{$ifNull: ['$videos', 0]}, 1, 0]}}}},
{$addFields: {_id: '$_id._id'}}])
Output:
{
"_id" : ObjectId("58f9f7a91fb2bf7c46abe5d6"),
"video_ids" : [ ],
"videos" : 0
}
{
"_id" : ObjectId("58f9f7a91fb2bf7c46abe5d6"),
"video_ids" : [
"video1",
"video2"
],
"videos" : 2
}

New aggregation feature with Mongo 3.2 driver, using Java

I want to perform an aggregation in Mongo 3.2 as explained here, but in Java:
https://docs.mongodb.org/master/reference/operator/aggregation/lookup/#pipe._S_lookup
At the moment my query object in java is very simple:
Document query = new Document();
query.append("employeId", employeId);
In addition to filtering by employeId, I would like to join this collection with company (where employee.company_id = company.id)
How can I do that in Java? It seems like I cannot find documentation of this new Mongo feature.
EDIT
Example of Employee collection:
{
"id" : 1,
"name" : "John",
"lastName" : "Moore",
"age" : 44,
"companyId": 10
}
Example of Company collection:
{
"id" : 10,
"companyName" : "Microsoft",
"numEmployee" : 100
}
Example of output expected
{
"id" : 1,
"name" : "John",
"lastName" : "Moore",
"companyId" : 10,
"companyName" : "Microsoft"
}
Running the following aggregation pipeline should give you the needed result
pipeline = [
{
"$match": {
"_id": employeeId
}
},
{
"$lookup": {
"from": "company",
"localField": "companyId",
"foreignField": "_id",
"as": "company"
}
},
{
"$project": {
"name": 1,
"lastName": 1,
"companyId": 1,
"companyName": "$company.companyName"
}
}
];
db.employee.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("employee");
// create the pipeline operations, first with the $match
DBObject match = new BasicDBObject("$match",
new BasicDBObject("_id", employeeId)
);
// build the $lookup operations
DBObject lookupFields = new BasicDBObject("from", "company");
lookupFields.put("localField", "companyId");
lookupFields.put("foreignField", "_id");
lookupFields.put("as", "company");
DBObject lookup = new BasicDBObject("$lookup", lookupFields);
// build the $project operations
DBObject projectFields = new BasicDBObject("name", 1);
projectFields.put("lastName", 1);
projectFields.put("companyId", 1);
projectFields.put("companyName", "$company.companyName");
DBObject project = new BasicDBObject("$project", projectFields);
List<DBObject> pipeline = Arrays.asList(match, lookup, project);
AggregationOutput output = coll.aggregate(pipeline);
for (DBObject result : output.results()) {
System.out.println(result);
}
}
}

Categories

Resources