how to update embeded document in mongodb using C# - c#

i have one collection in which i am doing insert/update operation. for insert i use the code:
MongoCollection<BsonDocument> tblCity = mydb.GetCollection<BsonDocument>("tblCity");
BsonDocument CollectionCity = new BsonDocument {
{ "CityCode", cityCode },
{ "CityName", cityName },
{ "stamps" , new BsonDocument {
{"ins", DateTime.Now},
{"upd", ""},
{"createUsr", UserId},
{"updUsr", ""},
{"Ins_Ip", ""},
{"Upd_IP", GetIP()}
}
}
};
tblCity.Insert(CollectionCity);
it is working fine. but while i am updating i am using code:
MongoCollection <BsonDocument> tblCity = mydb.GetCollection<BsonDocument>("tblCity");
var query = new QueryDocument { { "City_strCode", cityCode } };
var update = new UpdateDocument {
{ "$set", new BsonDocument("City_strName", cityName) },
{ "stamps" , new BsonDocument{
{"upd", DateTime.Now},
{"updUsr", ""},
{"Upd_IP", GetIP()
}}
}};
tblCity.Update(query, update);
But problem is that with out changing the ins date i want to update upd field. But it is removing the ins field and updating the upd field. I am trying a lot of ways but not able to get any solution. Please suggest something....Even I got some links based on this and tried.. but none of them workout.

You'll need to fix your use of $set and the query.
Your query doesn't match with the field name in the inserted document.
var query = new QueryDocument { { "CityCode", cityCode } };
If you're using $set, then pass all of the fields you want to change as part of the BsonDocument:
var query = new QueryDocument { { "CityCode", cityCode } };
var update = new UpdateDocument {
{ "$set", new BsonDocument {
{ "CityName", "San Fran"},
{ "stamps.upd" , DateTime.Now()},
{ "stamps.updUsr", ""},
{ "stamps.Upd_IP", "10.0.0.1" }
}}};

Related

How can I create an On-Demand DynamoDB table in C#?

I cannot seem to find an example of creating an On-Demand DynamoDB table in C#.
The C# examples on AWS only describes how to create a table with provisioned throughput.
I'm surprised by #MaYaN's answer, I've got it working nicely with
CreateTableRequest createRequest = new CreateTableRequest
{
TableName = "Foo",
AttributeDefinitions = new List<AttributeDefinition> {
new AttributeDefinition {
AttributeName = "Id",
AttributeType = ScalarAttributeType.S,
}
},
KeySchema = new List<KeySchemaElement> {
new KeySchemaElement("Id", KeyType.HASH)
},
BillingMode = BillingMode.PAY_PER_REQUEST
};
In my opinion the way this is supported in the SDK is unintuitive.
One would need to first create a table with a default ProvisionedThroughput then update the table and set the billing to: PAY_PER_REQUEST
CreateTableRequest createRequest = new CreateTableRequest
{
TableName = "Foo",
AttributeDefinitions = new List<AttributeDefinition> {
new AttributeDefinition {
AttributeName = "Id",
AttributeType = ScalarAttributeType.S,
}
},
KeySchema = new List<KeySchemaElement> {
new KeySchemaElement("Id", KeyType.HASH)
},
ProvisionedThroughput = new ProvisionedThroughput(1, 1)
};
await client.CreateTableAsync(createRequest);
// Wait for it to be created
await client.UpdateTableAsync(new UpdateTableRequest
{
TableName = name,
BillingMode = BillingMode.PAY_PER_REQUEST
});

List of maps in a DynamoDB data model

We have a data model with defined properties, but one of the properties allows for dynamic metadata (a list of maps or dictionaries). Using the document model, this property maps fine to a list of Document, however, when I'm having trouble getting this dynamic property to map to anything using DataModel. Is there a way to map dynamic data to documents inside a model class property?
Attempting to map it as a list of dictionaries (which matches the structure of the metadata) fails with the below error:
public List<Dictionary<string, object>> Events { get; set; }
Unable to convert [Amazon.DynamoDBv2.DocumentModel.Document] of type
Amazon.DynamoDBv2.DocumentModel.Document to
System.Collections.Generic.Dictionary`
Using a type of List<Document> got me the closest, which it now lists out 39 documents, but all the Documents have 0 keys, 0 values.
public List<Document> Events { get; set; }
Ex:
document["Events"].AsListOfDocument().First(); // works, contains the keys and values
datamodel.Events.First(); // does not work, it is an empty document
I know this is a quite old but hopefully this might help somebody else struggling with this.
Hi Devon,
In case you are trying to create the object to send it to your DynamoDB you can try mapping arbitrary data just as stated in AWS documentation for .NET
Here is the code from the documentation:
try
{
DynamoDBContext context = new DynamoDBContext(client);
// 1. Create a book.
DimensionType myBookDimensions = new DimensionType()
{
Length = 8M,
Height = 11M,
Thickness = 0.5M
};
Book myBook = new Book
{
Id = 501,
Title = "AWS SDK for .NET Object Persistence Model Handling Arbitrary Data",
ISBN = "999-9999999999",
BookAuthors = new List<string> { "Author 1", "Author 2" },
Dimensions = myBookDimensions
};
context.Save(myBook);
Once you have your data in the database you can append a new map to the list with something on the lines of:
var request = new UpdateItemRequest
{
TableName = "TableName",
Key = new Dictionary<string, AttributeValue>() { { "PartitionKey", new AttributeValue { S = "value" } } },
ExpressionAttributeNames = new Dictionary<string, string>()
{
{ "#A", "A" }
},
ExpressionAttributeValues = new Dictionary<string, AttributeValue>()
{
{
":val", new AttributeValue
{
L = new List<AttributeValue>()
{
{
new AttributeValue
{
M = new Dictionary<string, AttributeValue>()
{
{ "Address", new AttributeValue{S = "Value" } },
{ "Latitude", new AttributeValue { S = position.Latitude.ToString() } },
{ "Longitude", new AttributeValue { S = position.Longitude.ToString() } }
}
}
}
}
}
}
},
UpdateExpression = "SET #A = list_append(#A, :val)"
};
try
{
var response = await client.UpdateItemAsync(request);
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
This did the trick for me, I hope it does for someone else.
.
.
.
PS: BTW this is my first answer in Stackoverflow and it feels nice to try to contribute when I have came here multiple times for answers that saved me time jajajaja

Retrieving Data from DynamoDB using AWSSDK.net (core version 3.3.5 and AWSSDK.DynamoDBv2 version 3.3.1)

I am trying to retrieve the data from Dynamo DB based on a search criteria using Scan request. I am following the steps mentioned in http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/LowLevelDotNetScanning.html" page. My DynamoDB table contains more than 1 million records. I know that by using the do-while loop and ExclusiveStartKey we can fetch the records from dynamo DB. but in my case I can not wait till search process is complete as this will hang my angularJS UI. instead I want to progressively load the data with out waiting for the search process to complete. How we can do that.?
sample request:
var lastEvaluatedKey = new Dictionary<string, AttributeValue>(); ;
AmazonDynamoDBClient amazonDynamoDbClient= new AmazonDynamoDBClient()
var filterExpression = "#aws_s3_bucket = :v_aws_s3_bucket and contains(#aws_s3_key,:v_aws_s3_key)";
var projectExpression = "#aws_s3_key,filename,#region,aws_s3_bucket,#projecttype,folder,#siteid,locationname,createdon,modifiedon";
do
{
var request = new ScanRequest
{
TableName = "Test1",
ExclusiveStartKey=lastEvaluatedKey,
FilterExpression = filterExpression,
ExpressionAttributeNames = new Dictionary<string, string>
{
{ "#region", "region" },
{ "#siteid", "siteid" },
{ "#projecttype", "projecttype" },
{ "#aws_s3_key", "aws_s3_key" },
{ "#aws_s3_bucket", "aws_s3_bucket" }
},
ExpressionAttributeValues = new Dictionary<string, AttributeValue> {
{":v_aws_s3_bucket", new AttributeValue { S = "sampleBucket"}},
{":v_aws_s3_key", new AttributeValue { S = "92226"}}
},
ConsistentRead = true,
ProjectionExpression = projectExpression
};
response = amazonDynamoDbClient.Scan(request);
lastEvaluatedKey = response.LastEvaluatedKey;}while(lastEvaluatedKey!=null && lastEvaluatedKey.count()!=0)
I tried executing the above request with out using do-while loop and saved the ExclusiveStartKey for the next request it throws error the "The provided starting key is invalid: One or more parameter values were invalid: Null attribute value types must have the value of true".
any help on this issue will be helpful...
The error you're getting appears to be because you're setting ExclusiveStartKey on the request without setting any values for its parameters. Notice how you aren't updating request.ExclusiveStartKey after you get your response. Obviously, if you don't do that, the scan won't know where to pick up again when you hit your limit. See below.
AmazonDynamoDBClient amazonDynamoDbClient= new AmazonDynamoDBClient()
var filterExpression = "#aws_s3_bucket = :v_aws_s3_bucket and contains(#aws_s3_key,:v_aws_s3_key)";
var projectExpression = "#aws_s3_key,filename,#region,aws_s3_bucket,#projecttype,folder,#siteid,locationname,createdon,modifiedon";
ScanRequest request = new ScanRequest
{
TableName = "Test1",
FilterExpression = filterExpression,
ExpressionAttributeNames = new Dictionary<string, string>
{
{ "#region", "region" },
{ "#siteid", "siteid" },
{ "#projecttype", "projecttype" },
{ "#aws_s3_key", "aws_s3_key" },
{ "#aws_s3_bucket", "aws_s3_bucket" }
},
ExpressionAttributeValues = new Dictionary<string, AttributeValue> {
{":v_aws_s3_bucket", new AttributeValue { S = "sampleBucket"}},
{":v_aws_s3_key", new AttributeValue { S = "92226"}}
},
ConsistentRead = true,
ProjectionExpression = projectExpression
};
do
{
response = amazonDynamoDbClient.Scan(request);
request.ExclusiveStartKey = response.LastEvaluatedKey;
} while (response.lastEvaluatedKey.Count != 0);

How to use "Or" statement in MongoDB C# Driver?

I am facing problem while Querying the following in MongoDB C#. My code in mongo client is
db.collection.find( { $or: [ { quantity: { $lt: 20 } }, { price: 10 } ,{price:100},{name:"x"}] } )
but how to query the same in C#.
I was able to query the following mongo client code statement
db.collection.find({type:"food"},{name:1,quantity:1})
as
var match = new BsonDocument() { { "$match", new BsonDocument { {"type":"food" } } } };
var project = new BsonDocument(){ { "$project", new BsonDocument{ { "name", 1 } { "quantity", 1 } } } };
AggregateArgs AggregationPipeline = new AggregateArgs() { Pipeline = new[] { match, project } };
var aggregate = Collection.Aggregate(AggregationPipeline);
I am using Mongo C Sharp Driver 1.9.2.
Thanks.
First, add a builder:
var builder = Builders<BsonDocument>.Filter;
Then a filter like this:
var filter = builder.Lt("quantity", 20) | builder.Eq("price", 10) | other stuff)
And finally something like:
db.collection.Find(filter).ToList();

MongoDB Aggregate function in C#

I am trying to display/list data after using aggregation function but it isn't happening.
This code works absolutely fine.
var connectionstring = "mongodb://localhost:27017";
var client = new MongoClient(connectionstring);
var db = client.GetDatabase("school");
var col = db.GetCollection<BsonDocument>("students");
var filter = new BsonDocument("type", "homework");
var filter2 = Builders<BsonDocument>.Filter.Eq("scores.type", "homework");
var myresults = await col.Find(filter2)
.Limit(2)
.Project("{name:1,scores:1,_id:0}")
.Sort("{score:1}")
.ToListAsync();
foreach (var result in myresults)
{
Console.WriteLine(result);
}
This code fetches document as it should however when I replace
var myresults = await col.Find(filter2)
.Limit(2)
.Project("{name:1,scores:1,_id:0}")
.Sort("{score:1}")
.ToListAsync();
with this
var myresults = await col.Aggregate()
.Unwind("{$scores}")
.Group(new BsonDocument { { "_id", "$_id" }, { "lowscore", new BsonDocument("$min", "$scores.score") } })
//.Group("{_id:'$_id',lowscore:{$min:'$scores.score'}}")
.ToListAsync();
No record is being pulled.
I do not want to use Pipeline method. I simply want to display the result obtained via aggregate function.
This is my Mongo Query (I want the same result as this in C#)-
db.students.aggregate([{$sort:{_id:-1}},{$unwind:"$scores"},{$group:{_id:"$_id", lowscore:{"$min":"$scores.score"}}}])
Building aggregation pipeline is bit tricky.
Try:
var pipeline = new BsonDocument[] {
new BsonDocument{ { "$sort", new BsonDocument("_id", 1) }},
new BsonDocument{{"$unwind", "$scores"}},
new BsonDocument{{"$group", new BsonDocument{
{"_id", "$_id"},
{"lowscore",new BsonDocument{
{"$min","$scores.score"}}
}}
}}
};
var result = collection.Aggregate<BsonDocument> (pipeline).ToListAsync();
If you do pipeline.ToJson(), you'll get following JSON equivalent string which is same as of your original and tested MongoShell query.
[
{
"$sort": {
"_id": 1
}
},
{
"$unwind": "$scores"
},
{
"$group": {
"_id": "$_id",
"lowscore": {
"$min": "$scores.score"
}
}
}
]
This is wrong... {$scores} isn't even valid json. Remove the curly braces and the dollar sign from the $unwind directive.
The parameter name is field, so you need to provide a field name to it.
Try with writing only $score instead of #scores.score. may be it helpful.
db.students.aggregate([{$sort:{_id:-1}},{$unwind:"$scores"},{$group:{_id:"$_id", lowscore:{"$min":"$score"}}}])

Categories