MongoDb isDeleted attribute - not always exist - mongodb

When fetching records in mongoDb using QueryBuilder:
DBObject query = QueryBuilder.start("field1).is("foo").and("field2").is("bar").get();
Sometimes isDeleted attribute will be on the record,
But sometimes it will not be there,
How do I use QueryBuilder to tell MongoDb to fetch records where isDeleted attribute is not true, or not there..
Using expressions I can do:
myOr.add(new BasicDBObject("isDeleted", bool));
myOr.add(new BasicDBObject("isDeleted", new BasicDBObject("$exists", bool)));
DBObject query = baseFilter.append("$or", myOr);

You essentially want the following mongodb query
var query = {
"$or": [
{ "isDeleted": false },
{ "isDeleted": { "$exists": false } }
]
}
db.collection.find(query)
Using the QueryBuilder, this will translate to
QueryBuilder query = new QueryBuilder();
query.or(
QueryBuilder.start("isDeleted").is(false).get(),
QueryBuilder.start("isDeleted").exists(false).get()
);
DBCursor cursor = collection.find(query.get());

Related

How can I fetch the size of array in mongodb using springboot?

I'm new to springboot and mongodb as well. I have the following json document in mongodb
Note: *Name of database is Friends and name of collection is Friend. It has around 118k documents.
One sample document:
[{
"_id":"abhj",
"id":"abhj",
"Main_array":[
{
"number":12345,
"pincode":247800,
"address": [
"vasant"
"vihar"
"kota"
]
}
],
}]
There is Main_array inside which there is an object inside which we have address which is an array.
I want to fetch the size of this address array.
I tried this but it didn't work.
Note: I have to use MongoClient.
MongoDatabase database = mongoClient.getDatabase("Friends");
MongoCollection<Document> collection = database.getCollection("Friend");
BasicDBObject filter = new BasicDBObject("Main_Array.0.address", new BasicDBObject("$exists", "true"));
collection.find(filter).forEach((Consumer<Document>) doc -> {
Object obj = doc.get("Main_array.address")
}
But I got null value in obj.
You can use following aggregation to find out the size.
here is the code
db.collection.aggregate([
{
$addFields: {
Main_array: {
"$map": {
"input": "$Main_array",
"in": {
number: "$$this.number",
pincode: "$$this.pincode",
addressSize: {
$size: "$$this.address"
}
}
}
}
}
}
])
Working Mongo playground
There is a TRICK to convert aggregations... The java code might be
#Autowired
private MongoTemplate mongoTemplate;
public List<YOUR_CONVERTER_CLASS> test() {
Aggregation aggregation = Aggregation.newAggregation(
l-> new Document("$addFields",
new Document("Main_array",
new Document("$map",
new Document("input","$Main_array")
.append("in",
new Document("number","$$this.number")
.append("pincode","$$this.pincode")
.append("addressSize",
new Document("$size","$$this.address")
)
)
)
)
)
).withOptions(AggregationOptions.builder().allowDiskUse(Boolean.TRUE).build());
return mongoTemplate.aggregate(aggregation, mongoTemplate.getCollectionName(YOUR_COLLECTION_CLASS.class), YOUR_CONVERTER_CLASS.class).getMappedResults();
}

MongoDB - Update One Field or Another

I'm pretty new to MongoDB so this might be my inexperience with it. I'm trying to do an upsert that when a record is found it will update multiple fields based on multiple conditions.
I have the following record in a collection:
{
modelId: "5e68c7eaa0887971ea6ef54c",
versionId: 999,
timeStamp: "1/1/2020",
oldValue: 'Blue',
newValue: 'Red'
}
I'm trying to satisfy the following conditions with a single upsert statement in order to avoid making multiple trips to the DB (based on the query that a document matching the modelId and versionId is found:
If timeStamp of new record is before (lt) the existing document then update oldValue
If timeStamp of new record is after (gt) the existing document then update newValue
If matching records is not found insert the new record.
In psuedo code terms I'm trying to do this with the upsert statement:
existingRecord = item in collection matching modelId and versionId
if(existingRecord = null)
{
//insert newRecord
}
if(newRecord.timeStamp < existingRecord.timeStamp)
{
existingRecord.oldValue = newRecord.oldValue
existingRecord.timeStamp = newRecord.timeStamp
}
else if(newRecord.timeStamp > existingRecord.timeStamp)
{
existingRecord.newValue = newRecord.newValue
existingRecord.timeStamp = newRecord.timeStamp
}
I've seen the possibility to do an upsert based on the condition of a date, something like:
db.collection.update( { id:o.id, date: { $lt:o.date } }, {$set : { o }}, {upsert:true} );
I don't know how to expand that to be able to update either the oldValue or the newValue based on the timeStamp value.
I'm planning on having a good amount of records inserted into the collection every day, estimate around 1MM, I'd hate to have to do a find() and then an update() for each record.
I'm using Mongo 4.0 and would appreciate any advice.
Thanks!
Well, in version 4.0, you are not allowed to use the conditions in the update query. Hence, you end up firing two queries instead.
db.collection.update({condition}, { $set: { o } }, { multi: true ,upsert:true });
db.collection.update({!condition}, { $set: { n } }, { multi: true ,upsert:true });
However, in version 4.2, added db.collection.update pipeline, in which the aggregation is allowed.
And, it contains only the following aggregation stages:
$addFields and its alias $set
$project and its alias $unset
$replaceRoot and its alias $replaceWith.
Hope this will help :)
Update
I have added the $set stage to update the document. It will update the if timestamp condition is true else it will not update. and applies the same for other condition.
I have used the long value of timestamp you can use according to you case.
db.collection.update(
{
modelId: "5e68c7eaa0887971ea6ef54c",
versionId: 999,
},
[
{
$set:{
"oldValue":{
$cond:[
{
$lt:[
"timestamp",
1598598257000
]
},
"green",
"$oldValue"
]
}
}
},
{
$set:{
"newValue":{
$cond:[
{
$gt:[
"timestamp",
1518598257000
]
},
"pink",
"$newValue"
]
}
}
}
]
)

mongodb update a key to all documents using forEach

I want to update in Mongo the 'order' field to all of my documents so they will be 1..2..3..4....34.
After running this, they all have "order": "34".
What am I doing wrong?
var i = 1;
db.images.find().forEach(function() {
db.images.update(
{},
{ "$set": {"order": NumberInt(i)} },
{ multi: true }
);
i++;
})
multi : true means all documents matching the query will be updated. And your query is {}, which matches all the documents. So, basically you are updating the order of all the documents in every iteration.
Also, snapshot mode has to be enabled on the cursor to ensure that the same document isn't returned more than once.
You could try this:
var i = 1;
db.images.find().snapshot().forEach(function(image) {
db.images.update(
{"_id" : image._id},
{ "$set": {"order": NumberInt(i)} }
);
i++;
})
From a performance standpoint, it is better to use the bulk APIs. bulkwrite

modify array element's value with Java MongoDB driver

I want to modify array element using Java MongoDB driver. I am able to insert new pair to the array, but can't modify value corresponding to particular key.
How can I increase a by 2 in dummy array for document
{ "_id" : ObjectId("57a87614d03a435e4be44bb9"), "dummy" : [ { "a" : 1 }, { "b" : 5 } ] }
using Java MongoDB driver?
Here is what I've tried
BasicDBObject query = new BasicDBObject();
query.put("_id",doc_id_here);
BasicDBObject incValue = new BasicDBObject("dummy.$.a", 1);
BasicDBObject intModifier = new BasicDBObject("$inc", incValue);
coll.update(query, intModifier, false, false, WriteConcern.SAFE);
Your query in mongo shell
db.collection.update(
{ "_id": ObjectId("57a87614d03a435e4be44bb9") },
{ $inc: { "dummy.$.a": 1 } }
);
will result in error
The positional operator did not find the match needed from the query.
Unexpanded update: dummy.$.a
because in order to use positional $ operator for dummy array you need to set condition on this array in your query
db.collection.update(
{ "_id": ObjectId("57a87614d03a435e4be44bb9"), "dummy.a": { $exists: true } },
{ $inc: { "dummy.$.a": 1 } }
);
and then it will increment a as you expect.
With Java MongoDB driver it will be
BasicDBObject query = new BasicDBObject();
query.put("_id", new ObjectId("57a87614d03a435e4be44bb9"));
query.put("dummy.a", new BasicDBObject("$exists", true));
BasicDBObject incValue = new BasicDBObject("dummy.$.a", 1);
BasicDBObject intModifier = new BasicDBObject("$inc", incValue);
coll.update(query, intModifier, false, false, WriteConcern.SAFE);
Advice: before trying to construct your query with Java MongoDB Driver first try if it works in mongo shell.

update a document in mongoDB using JAVA

I'm just starting to learn mongoDB using JAVA. I have the the following document in mongo
{
"_id": {
"$oid": "513fa587c5d0cf174eb9b1f8"
},
"suitename": "test_suite_name",
"testname": "test_name]",
"milestones": [
{
"milestone_id": 45
}
]
}
I have a compound key on suitename, testname, and milestone_id. I have to process a file which has these three fields. I create a simple DBObject query and check if count != 0
BasicDBObject query = new BasicDBObject();
query.put("suitename", testsuite);
query.put("testname", testcase);
query.put("milestones.milestone_id", SampleProgram.milestone_id);
If count == 0 --> add document in mongo -> this seems to work fine
What I am trying to figure out is:
If I have a new value of milestone_id in my file, I just need to add a milestone to some existing document's milestone array. Existing document is determined based on suitename AND testname.
So if milestone_id = 10, the document should look like
{
"_id": {
"$oid": "513fa587c5d0cf174eb9b1f8"
},
"suitename": "test_suite_name",
"testname": "test_name]",
"milestones": [
{
"milestone_id": 45
},
{
"milestone_id": 10
}
]
}
How can I accomplish this?
Thanks
This can be accomplished with the $push operator which appends values to an array and the update(…) method.
BasicDBObject query = new BasicDBObject();
query.put("suitename", testsuite);
query.put("testname", testcase);
BasicDBObject push = new BasicDBObject();
push.put("$push",
new BasicDBObject("milestones",
new BasicDBObject("milestone_id", SampleProgram.milestone_id)));
yourCollection.update(query, push);
BasicDBObject newDocument = new BasicDBObject();
newDocument.append("$set", new BasicDBObject().append("clients", 110));
BasicDBObject searchQuery = new BasicDBObject().append("hosting", "hostB");
collection.update(searchQuery, newDocument);