MongoDB udate query using class object in C#? - mongodb

I am storing class object in mongodb like below,
try
{
Sample risk = new Sample();
risk.Name = "ABC";
risk.Enable = true;
risk.Sender = "IBM";
risk.Target = "CITI";
MongoServer server = MongoServer.Create("mongodb://localhost");
MongoDatabase db = server.GetDatabase("DATABASE");
db.GetCollection<StockQuote>("SMAPLETABLE").Insert(risk);
}
catch (Exception e)
{
MessageBox.Show("Error");
}
now i want to to update that same class instance like db.GetCollection<StockQuote>("SMAPLETABLE").Insert(risk); how can i do this one.

There is two approaches two update document:
1.Via Save method and update etire document
db.GetCollection<StockQuote>("SMAPLETABLE").Save(risk);
2.Via atomic update: update part of document. For example if you need update Enable field of document with Name "ABC":
db.GetCollection<StockQuote>("SMAPLETABLE").Update(
Query.EQ("Name", "ABC"),
Update.Set("Enable", false));
Some notes:
With atomic updates you can avoid concurrency issues. Atomic update it is like transaction within one document.

Related

Java - Insert/Update with MongoDB collection bulkWrite

I am very new to MongoDB. Trying to understand the best option to perform Bulk Write in MongoDB. I want to periodically refresh my Application collection. The key's for documents are AppID, AppName and AppStatus.
Below are the actions I want to perform in every run -
Find the AppID in Application collection.
If not exists, perform an insert
If exists, only update the value of AppStatus key.
List<Application> applist = getAppList(); // List contains All the Application
private final MongoClient mongoClient;
private final MongoTemplate mongoTemplate;
MongoCollection<Document> collection =
mongoTemplate.getDb().getCollection("Application");
collection.bulkWrite (????);
How do I loop over the appList and perform a bulk insert/update ?
You can use org.springframework.data.mongodb.core.BulkOperations to perform bulk update/insert/upsert/delete operations.
List<Application> applist = getAppList();
List<Pair<Query, Update>> updates = new ArrayList<>(applist.size());
applist.forEach(application -> {
Query query = Query.query(Criteria.where("AppID").is(application.getAppID()));
Update update = new Update();
update.set("AppID", application.getAppID());
update.set("AppName", application.getAppName());
update.set("AppStatus", application.getAppStatus());
updates.add(Pair.of(query, update));
});
BulkOperations bulkOperations = mongoTemplate.bulkOps(BulkOperations.BulkMode.UNORDERED, "Application");
bulkOperations.upsert(updates);
bulkOperations.execute();

How do I skip duplicate documents in a bulk insert and ignore duplicates with a specific field c#

I need to insert many documents and ignore the duplicated docs.
Doc format:
_id:5b84e2588aceda018a974450
Name:"Jeff M"
Email:"jeff.m#xtrastaff.com"
Type:"Client"
UserId:Binary('Rw+KMGpSAECQ3gwCtfoKUg==')
UserImage:null
I want to check the duplication using the EmailId field when I am inserting. Insert only if it is not existing.
To prevent the duplicates being inserted you need a unique index which can be created in C# code:
public void CreateIndex()
{
var options = new CreateIndexOptions() { Unique = true };
var field = new StringFieldDefinition<Model>(nameof(Model.Email));
var indexDefinition = new IndexKeysDefinitionBuilder<Model>().Ascending(field);
Collection.Indexes.CreateOne(indexDefinition, options);
}
Then you can insert multiple documents using BulkWrite operation. The problem is that by default the processing will be stopped when first insert operation fails (which happens when you try to insert a duplicate) and you'll get an exception in C#. You can modify that by setting ordered parameter to false which means that all the inserts will be processed "in parallel" and you'll get one exception which aggregates all failed inserts. That exception is of type MongoBulkWriteException and you can try to catch it. So you can try following method:
public void InsertData(List<Model> data)
{
var writeOps = data.Select(x => new InsertOneModel<Model>(x));
try
{
Collection.BulkWrite(writeOps, new BulkWriteOptions() { IsOrdered = false });
}
catch (MongoBulkWriteException ex)
{
// will be thrown when there were any duplicates
}
}

using findAndModify in mongodb using grails gorm

I need to use findAndModify in my application with grails and mongoDB.
I used this code :
public static String getNextId(DB db, String seq_name) {
String sequence_collection = "seq"; // the name of the sequence collection
String sequence_field = "seq"; // the name of the field which holds the sequence
DBCollection seq = db.getCollection(sequence_collection); // get the collection (this will create it if needed)
// this object represents your "query", its analogous to a WHERE clause in SQL
DBObject query = new BasicDBObject();
query.put("_id", seq_name); // where _id = the input sequence name
// this object represents the "update" or the SET blah=blah in SQL
DBObject change = new BasicDBObject(sequence_field, 1);
DBObject update = new BasicDBObject("$inc", change); // the $inc here is a mongodb command for increment
// Atomically updates the sequence field and returns the value for you
DBObject res = seq.findAndModify(query, new BasicDBObject(), new BasicDBObject(), false, update, true, true);
return res.get(sequence_field).toString();
}
and it work successful. But now I want use findAndModify without native mongodb object, and with using GORM.
Is there any solution for this work?
There is not way to accomplish this without native API, you can however write your code a bit more compact like this:
def collection = Seq.collection
collection.findAndModify([_id: seq_name ], [ "\$inc": [seq:1] ])
Config your DataSource.groovy with db configurations.
Then define a Domain class:
Class Seq{
int seq
}
And use dynamic finder in a sevice:
Class SeqService {
String findAndModify(String seq_name) {
def seqInstance = Seq.get(seq_name)
if(seqInstance){
seqInstance.seq ++
seqInstance.save()
return seqInstance.seq.toString()
}
return '' //instance not found
}
}
Then make a call when you need that action:
def seqService
def id
.......
def result = seqService.findAndModify(id)
....

Capped collections using MongoDB and SpringData

I am trying to create a capped collection for logging using mongoTemplate. However my collection size is growing beyond the size I passed as arguments. Can anyone please help with this.
public synchronized MongoTemplate getTemplate() {
if (template == null) {
Mongo mongo = null;
mongo = new Mongo(addrs);
template = new MongoTemplate(mongo, this.dbName);
if(!template.collectionExists(HttpRequestEntity.class)){
CollectionOptions options = new CollectionOptions(4,4,true);
template.createCollection(HttpRequestEntity.class, options);
}
}
return template;
}
For saving I am calling save on this template instance
getTemplate().save(entity);
Got it working after I deleted the collection from mongo console. I guess it was use old meta data as template.collectionExists(HttpRequestEntity.class) was returning true.

How do I get the date a MongoDB collection was created using MongoDB C# driver?

I need to iterate through all of the collections in my MongoDB database and get the time when each of the collections was created (I understand that I could get the timestamp of each object in the collection, but I would rather not go that route if a simpler/faster method exists).
This should give you an idea of what I'm trying to do:
MongoDatabase _database;
// code elided
var result = _database.GetAllCollectionNames().Select(collectionName =>
{
_database.GetCollection( collectionName ) //.{GetCreatedDate())
});
As far as I know, MongoDB doesn't keep track of collection creation dates. However, it's really easy to do this yourself. Add a simple method, something like this, and use it whenever you create a new collection:
public static void CreateCollectionWithMetadata(string collectionName)
{
var result = _db.CreateCollection(collectionName);
if (result.Ok)
{
var collectionMetadata = _db.GetCollection("collectionMetadata");
collectionMetadata.Insert(new { Id = collectionName, Created = DateTime.Now });
}
}
Then whenever you need the information just query the collectionMetadata collection. Or, if you want to use an extension method like in your example, do something like this:
public static DateTime GetCreatedDate(this MongoCollection collection)
{
var collectionMetadata = _db.GetCollection("collectionMetadata");
var metadata = collectionMetadata.FindOneById(collection.Name);
var created = metadata["Created"].AsDateTime;
return created;
}
The "creation date" is not part of the collection's metadata. A collection does not "know" when it was created. Some indexes have an ObjectId() which implies a timestamp, but this is not consistent and not reliable.
Therefore, I don't believe this can be done.
Like Mr. Gates VP say, there is no way using the metadata... but you can get the oldest document in the collection and get it from the _id.
Moreover, you can insert an "empty" document in the collection for that purpose without recurring to maintain another collection.
And it's very easy get the oldest document:
old = db.collection.find({}, {_id}).sort({_id: 1}).limit(1)
dat = old._id.getTimestamp()
By default, all collection has an index over _id field, making the find efficient.
(I using MongoDb 3.6)
Seems like it's some necroposting but anyway: I tried to find an answer and got it:
Checked it in Mongo shell, don't know how to use in C#:
// db.payload_metadata.find().limit(1)
ObjectId("60379be2bec7a3c17e6b662b").getTimestamp()
ISODate("2021-02-25T12:45:22Z")