Pairs insertion/retrieval in/from field - java

I am trying to insert pairs in a mongoDB Document. This how i am doing it so far:
private static MongoCollection<Document> getCollectionn(String link, String coll){
...
}
public static void main(String[] args) {
MongoCollection<Document> fb_users;
fb_users = getCollectionn("mongodb://...", "fb_users2");
Document myDoc;
BasicDBObject query = new BasicDBObject();
query.put("fbid", "1");
myDoc = fb_users.find(query).first();
int postId=5;
int rating=3;
fb_users.updateOne(myDoc,
new Document("$push", new Document("ratings", java.util.Arrays.asList(rating, postId))));
Object a = myDoc.get("ratings");
ArrayList<Document> b = (ArrayList<Document>) a;
System.out.println(b.get(0);//prints [3, 5]
}
This is how the array document is inserted in the collection after two runs:
(the document already exists)
{
"_id": {
"$oid": "56f173b5e4b04eaac6531030"
},
"fbid": "1",
"ratings": [
[
3,
5
],
[
3,
5
]
]
}
In println i get the result [3, 5]
My question is this:
How can i recieve the numder 3 and the number 5 seperatly? Should i insert the documents with another way? Iam using mongo java driver 3.2.0.

Ok i found the solution. Here it is:
Document myDoc;
BasicDBObject query = new BasicDBObject();
query.put("fbid", "1");
myDoc = fb_users.find(query).first();
int postId=5;
int rating=3;
Document listItem = new Document("ratings", new Document(String.valueOf(rating), String.valueOf(postId)));
Document updateQuery = new Document("$push", listItem);
fb_users.updateOne(myDoc, updateQuery);
MongoCursor<Document> curs = fb_users.find(query).iterator();
ArrayList<Document> list = (ArrayList<Document>) myDoc.get("ratings");
Iterator<Document> iterateList = list .iterator();
while(iterateList .hasNext()){
Document pair = iterateList .next();
for(String element : pair.keySet()){
System.out.println(element + " " + pair.get(element));
}
}
and the json format is and should be like this:
{
"_id": {
"$oid": "56f173b5e4b04eaac6531030"
},
"fbid": "1",
"ratings": [
{
"3": "5"
},
{
"3": "5"
}
]
}

Related

MongoDb - not adding array object at proper place instead its adding it to root

I have only one collection in my Mongodb and that is as follows
[
{
"_id": {
"timestamp": 1626753855,
"date": "2021-07-20T04:04:15.000+00:00"
},
"metadata": [
{
"country": "Canada",
"authors": [
{
"author": "Test Author",
"Books": [
{
"name": "Sample Book",
"code": "JCAR"
}
]
}
]
}
]
}
]
The method I am using is as follows
private void updateAuthorsMetadata(AuthorMetadata authorMetadata) {
MongoCollection<Document> collection = mDatabase.getCollection(authorMetadataCollection);
Bson eqFilter = eq("metadata.country", "Canada");
FindIterable<Document> itrDoc = collection.find(eqFilter);
if (itrDoc.first() == null) {
Document document = new Document();
document.append("metadata",
Arrays.asList(new Document("country", authorMetadata.getCountry()).append("authors",
Arrays.asList(new Document("author", authorMetadata.getAuthorName()).append("Books",
Arrays.asList(new Document("name", authorMetadata.getBookName()).append("code",
authorMetadata.getBookCode())))))));
collection.insertOne(document);
} else {
Bson andFilter = and(eq("metadata.country", "Canada"),
eq("metadata.authors.author", "John Doe"));
FindIterable<Document> itrAndDoc = collection.find(docFilter);
if (itrAndDoc.first() == null) {
Document doc = new Document("author", "John Doe).append("Books",
Arrays.asList(new Document("name", "Some Book").append("code",
"SBD4")));
Bson update = push("metadata[].authors", doc);
UpdateResult result = collection.updateOne(eqFilter, update);
}
}
}
The issue I am facing is that when I update collection at
else block
then it is adding the document to the root instead of adding it to the authors array, as shown in the image below.
How I can update it at the proper location i.e. adding to "authors" array? I am using Java driver v-3.12.7.
Finally, I figured it out. Anyone out there struggling with same issue can refer to this method. The issue was positional operators, some forums says that multiple positional operators can't be used below v 3.x.x but I am using 3.12.x and still had this issue. I think the way I am doing is not best/optimal but it works and if anyone direct me to the right direction then it would be great.
private void updateAuthorMetadata(AuthorMetadata authorMetadata) {
MongoCollection<Document> collection = mDatabase.getCollection(authorMetadataCollection);
Bson bsonEqFilter = eq("metadata.country", authorMetadata.getCountry());
FindIterable<Document> itrDoc = collection.find(bsonEqFilter);
Document found = itrDoc.first();
if (found == null) {
Document document = new Document();
document.append("metadata",
Arrays.asList(new Document("country", authorMetadata.getCountry()).append("authors",
Arrays.asList(new Document("author", authorMetadata.getAuthor()).append("books",
Arrays.asList(new Document("name", authorMetadata.getBookName())
.append("code", authorMetadata.getBookCode())))))));
collection.insertOne(document);
} else {
Bson bsonAndFilter = and(eq("metadata.country", authorMetadata.getCountry()),
eq("metadata.authors.author", authorMetadata.getAuthor()));
FindIterable<Document> itrAndDoc = collection.find(bsonAndFilter);
if (itrAndDoc.first() == null) {
Document document = new Document("author", authorMetadata.getAuthor()).append("Books",
Arrays.asList(new Document("name", authorMetadata.getBookName()).append("code",
authorMetadata.getBookCode())));
Bson update = push("metadata.$.authors", document);
UpdateResult result = collection.updateOne(bsonEqFilter, update);
} else {
Bson bsonMoreAndFilter = and(eq("metadata.country", authorMetadata.getCountry()),
eq("metadata.authors.author", authorMetadata.getAuthor()),
eq("metadata.authors.books.code", authorMetadata.getBookCode()));
FindIterable<Document> itrMoreAndDoc = collection.find(bsonMoreAndFilter);
if (itrMoreAndDoc.first() == null) {
Document docBooks = new Document("name", authorMetadata.getBookName()).append("code",
authorMetadata.getBookCode());
Bson update = push("metadata.0.authors.$.books", docBooks);
UpdateResult result = collection.updateOne(bsonAndFilter, update);
}
}
}
}

Spring Data MongoDB Aggregation return empty data but works on Compass with the same pipeline

I have a problem to query the mongoDB data. Here is the document:
{
productId:1,
warehouses:[
warehouseId:1,
productBatch:[
{
unitPrice:15.5,
quantity:1000,
expireSearchTimestamp:14145555545,
currentQuantity:50
},{
unitPrice:17.5,
quantity:1000,
expireSearchTimestamp:14145555545,
currentQuantity:50
}
]
]
}
and by code is
public List<ProductSearchResult> findCustomSearch(List<Integer> medicines,
List<Integer> warehousesIds, int quantity)
{
UnwindOperation unwind1 = Aggregation.unwind("warehouses");
UnwindOperation unwind2 = Aggregation.unwind("warehouses.productBatch");
ProjectionOperation project = Aggregation.project("warehouses.productBatch");
MatchOperation match = Aggregation.match(Criteria.where("productId").in(productIds)
.and("warehouses.warehouseId").in(warehousesIds)
.and("warehouses.productBatch.currentQuantity").gte(quantity));
SortOperation sort = Aggregation.sort(Direction.ASC, "productBatch.unitPrice");
LimitOperation limit = Aggregation.limit(3);
Aggregation aggregation = Aggregation
.newAggregation(unwind1, unwind2, project, sort, limit)
.withOptions(Aggregation.newAggregationOptions().allowDiskUse(true).explain(true)
.cursor(new BasicDBObject()).build());
AggregationResults<ProductSearchResult> results = mongoTemplate.aggregate(aggregation,
"medicine", ProductSearchResult.class);
List<ProductSearchResult> mappedResults = results.getMappedResults();
return mappedResults;
}
this is the function output
[
{
"$unwind": "$warehouses"
},
{
"$unwind": "$warehouses.productBatch"
},
{
"$match": {
"productId": {
"$in": [
20,
21
]
},
"warehouses.warehouse_id": {
"$in": [
1,
2,
3,
4,
5
]
},
"warehouses.productBatch.currentQuantity": {
"$gte": 10
}
}
},
{
"$project": {
"medicine_search": "$warehouses.productBatch"
}
},
{
"$sort": {
"productBatch.unitPrice": 1
}
},
{
"$limit": 3
}
]
when I run this function I got empty list but according to mongo compass I got 3 element.
thanks
I don't know why this block of code not work but the following one is satisfy for me
public void finalTry(List<Integer> productIds,
List<Integer> warehousesIds, int q, int limitN)
{
DBCollection collection = mongoTemplate.getCollection("product");
DBObject limit = new BasicDBObject("$limit", limitN);
DBObject sort = new BasicDBObject("$sort",
new BasicDBObject("productBatch.unitPrice", 1));
DBObject unwind1 = new BasicDBObject("$unwind", "$warehouses");
DBObject unwind2 = new BasicDBObject("$unwind", "$warehouses.productBatch");
DBObject project = new BasicDBObject("$project",
new BasicDBObject("productBatch", "$warehouses.productBatch"));
DBObject match1 = new BasicDBObject("$match",
new BasicDBObject("productId", new BasicDBObject("$in", productIds)));
DBObject match2 = new BasicDBObject("$match", new BasicDBObject("warehouses.warehouseId",
new BasicDBObject("$in", warehousesIds)));
DBObject match3 = new BasicDBObject("$match", new BasicDBObject(
"warehouses.productBatch.currentQuantity", new BasicDBObject("$gte", q)));
List<DBObject> pipeline = Arrays.asList(match1, unwind1, match2, unwind2, match3, project,
sort, limit);
AggregationOutput output = collection.aggregate(pipeline);
for (DBObject d : output.results())
{
System.out.println(d)
}
}
Thanks

Combining multiple arrays for querying with MongoDB Java driver

I have the following JSON:
{"pid":"b00l16vp","categories":{"category1":["factual", "arts culture and the media", "history"]}}
{"pid":"b0079mpp","categories":{"category2":["childrens", "entertainment and comedy", "animation"],"category1":["signed"]}}
{“pid":"b00htbn3"}
{“pid":"b00gdhqw","categories":{"category2":["factual"],"category3":["scotland"],"category4":["lifestyle and leisure", "food and drink"],"category1":["entertainment", "games and quizzes"]}}
My intention is to query the categories object using an array of String by combining all of the arrays in a single array.
I have the following code:
String [] cats = ["childrens", "signed"]
BasicDBObject theProjections = new BasicDBObject()
for (int i = 1; i <= 5; i++) {
String identifier = "categories.category" + i
String cleanIdentifier = "\$" + identifier
//If the category does not exist, put in a blank category
def temp = [cleanIdentifier, []]
theMegaArray.add(new BasicDBObject('$ifNull', temp))
}
//The megaArray is the array created in the above loop which combines all arrays
BasicDBObject theData = new BasicDBObject('$setUnion', theMegaArray)
BasicDBObject theFilter = new BasicDBObject('input', theData)
theFilter.put("as", "megaArray")
//all of the values found in cats should match the megaArray
theFilter.put("cond", new BasicDBObject('$all', ["\$\$megaArray", cats]))
theProjections.put('$filter', theFilter)
FindIterable iterable = collection.find(criteria).projection(theProjections)
I have used this question to come to write this code so far. The $setUnion expects all of the fields to appear however in my JSON, there are a varied number of categrories arrays hence I have used the $ifNull to populate empty categories with []. The $filter has been used to query the cats array on the megaArray.
When running this I'm getting the following error:
Caused by: com.mongodb.MongoQueryException: Query failed with error code 2 and error message '>1 field in obj: { input: { $setUnion: [ { $ifNull: [ "$categories.category1", [] ] }, { $ifNull: [ "$categories.category2", [] ] }, { $ifNull: [ "$categories.category3", [] ] }, { $ifNull: [ "$categories.category4", [] ] }, { $ifNull: [ "$categories.category5", [] ] } ] }, as: "megaArray", cond: { $all: [ "$$megaArray", [ "factual" ] ] } }'
I'm not entirely sure what that means as the looks right. I should also note that the category object does not always exist but I'm not sure if this matters.
You can achieve the same result using the aggregation framework
To do this you can first project the data to create the 'megaArray' and then match against the new array.
String [] cats = new String[] {"childrens", "signed"};
List<DBObject> theMegaArray = new ArrayList<>();
BasicDBObject theProjections = new BasicDBObject();
for (int i = 1; i <= 5; i++) {
String identifier = "categories.category" + i;
String cleanIdentifier = "$" + identifier;
//If the category does not exist, put in a blank category
Object[] temp = new Object[] {cleanIdentifier, new Object[]{}};
theMegaArray.add(new BasicDBObject("$ifNull", temp));
}
theProjections.put("_id", 1);
theProjections.put("pid", 1);
theProjections.put("categories",1);
theProjections.put("allCategories", new BasicDBObject("$setUnion", theMegaArray));
BasicDBObject theFilter = new BasicDBObject("allCategories", new BasicDBObject("$all", cats));
List<BasicDBObject> pipeline = new ArrayList<>();
pipeline.add(new BasicDBObject("$project", theProjections));
pipeline.add(new BasicDBObject("$match", theFilter));
AggregateIterable iterable = collection.aggregate(pipeline);
The code sample above adds a new array called "allCategories" in the project stage and then matches against this new document.
Another projection stage could be added to remove the allCategories array from the final output
You can use the below aggregation pipeline.
Shell Query for reference:
db.collection.aggregate([{
"$project": {
"pid": 1,
"categories": 1,
"filter": {
"$eq": [{
"$setUnion": [{
"$ifNull": ["$categories.category1", []]
}, {
"$ifNull": ["$categories.category2", []]
}, {
"$ifNull": ["$categories.category3", []]
}, {
"$ifNull": ["$categories.category4", []]
}, {
"$ifNull": ["$categories.category5", []]
}]
},
["childrens", "signed"]
]
}
}
}, {
"$match": {
"filter": true
}
}])
Java Code:
String[] cats = {"childrens", "signed"};
// Combining the optional categories arrays
BasicDBList theMegaArray = new BasicDBList();
for (int i = 1; i <= 5; i++) {
String identifier = "categories.category" + i;
String cleanIdentifier = "$" + identifier;
theMegaArray.add(new BasicDBObject("$ifNull", Arrays.asList(cleanIdentifier, Collections.EMPTY_LIST)));
}
BasicDBObject theData = new BasicDBObject("$setUnion", theMegaArray);
// Add equals filter - Compare the arrays and output boolean filter field
BasicDBObject theFilter = new BasicDBObject("$eq", Arrays.asList(theData, cats));
// Add projections to keep the output fields
BasicDBObject theProjections = new BasicDBObject();
theProjections.put("filter", theFilter);
theProjections.put("pid", 1);
theProjections.put("categories", 1);
// Add $project stage
BasicDBObject theProject = new BasicDBObject("$project", theProjections);
// Add $match stage to compare the boolean filter field to true to keep matching documents
BasicDBObject theMatch = new BasicDBObject("$match", new BasicDBObject("filter", true));
// Add stages to piepline
BasicDBList pipeline = new BasicDBList();
pipeline.add(theProject);
pipeline.add(theMatch);
// Run aggregation
AggregateIterable iterable = collection.aggregate(pipeline);

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);
}
}
}

MongoDB Array modify Using 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} } },
] }
} )

Categories

Resources