How to "patch" a Document in DocumentDB using Mongo commands - c#

My code is below:
MyModel requestID = new MyModel
{
"id" = "123"
};
MyModel toUpdate = new MyModel
{
"is_cancelled" : true
};
FilterDefinition<MyModel> filter = requestID.ToBsonDocument();
UpdateDefinition<MyModel> update = toUpdate.ToBsonDocument();
collection.FindOneAndUpdate(filter, update);
My 1 Document in DocumentDB for example is:
{
"id": "123",
"delnum": "100001"
}
My toUpdate is:
{
"is_cancelled" : true
}
My expected document after FindOneAndUpdate is:
{
"id": "123",
"delnum": "100001",
"is_cancelled" : true
}
but what is happening is, it is replacing my document with id=123 to below:
{
"is_cancelled" : true
}
I would like to know if I am doing it wrong, or what my expectation outcome is not correct.
Edited Code:
MyModel requestID = new MyModel
{
"id" = "123"
};
MyModel toUpdate = new MyModel
{
"is_cancelled" : true
};
var builder = Builders<MyModel>.Update;
UpdateDefinition<MyModel> update =null;
toUpdate.GetType().GetProperties().ToList().ForEach(
x => update = builder.Set(x.Name, x.GetValue(toUpdate, null))
FilterDefinition<MyModel> filter = requestID.ToBsonDocument();
if (update == null) return;
collection.FindOneAndUpdate(filter, update);
EDIT:
code below what worked for me.
var filterData = Builders<MyModel>.Filter.Eq("id", "123"); //requestID
var updateData = new BsonDocumentUpdateDefinition<MyModel>(new BsonDocument("$set", toUpdate));
await collection.FindOneAndUpdateAsync(filter, updateData , new FindOneAndUpdateOptions<MyModel>() { IsUpsert = false });

You're not specifying what you want to update.
Mongo expects json to look like this:
{
"$set" : {
"is_cancelled" : true
}
}
You can use the update builder to make that easier:
var builder = Builders<MyModel>.Update;
var update = builder.Set("is_cancelled", true);
You can also chain multiple Set methods on the builder:
var update = builder.Set("a", 1).Set("b", 2);

Related

No array filter found for identifier '-1'

I am developing a .NET application with MongoDB, using C# driver 2.14.
My query is as follows:
I have an embedded array elements, eg:
{
"_id" : 1,
"Friends" : [
{
"_id" : 2,
"FirstName" : "Bob",
"LastName":"Marley",
"Gender":"Male",
...
},
{
"_id" : 3,
"Name" : "Jonson",
"LastName":"Charles",
"Gender":"Male",
...
},
{
"_id" : 4,
"Name" : "Bob",
"LastName":"",
"Gender":"Male",
...
}
]
}
which has multiple fields in it. I need to update all the values in one of the nested documents.
I have written a code as follows:
var filter1 = Builders<BsonDocument>.Filter.Eq("_id", 1);
var filter2 = Builders<BsonDocument>.Filter.ElemMatch<BsonValue>("Friends", new BsonDocument(){ {"_id", 2 }});
var update = Builders<BsonDocument>.Update.Set("Friends.$[-1]", BsonDocument.Parse(JsonConvert.SerializeObject(object)));
await collection.UpdateAsync(filter1&filter2, update);
I am getting the exception as:
No array filter found for identifier '-1'
Can anyone please suggest whether it's the right approach?
It is an invalid syntax/statement in MongoDB for
"Friends.$[-1]"
You need arrayFilter to update document in the nested array field.
using MongoDB.Bson;
var filter1 = Builders<BsonDocument>.Filter.Eq("_id", 1);
var filter2 = Builders<BsonDocument>.Filter.ElemMatch<BsonValue>("Friends"
, new BsonDocument() { { "_id", 2 } });
// Sample value to be updated
var obj = new
{
_id = 2,
FirstName = "Bobby",
LastName = "Marley",
Gender = "Female"
};
var arrayFilters = new[]
{
new BsonDocumentArrayFilterDefinition<BsonDocument>(
new BsonDocument("friend._id", 2)
)
};
var update = Builders<BsonDocument>.Update.Set("Friends.$[friend]", obj.ToBsonDocument());
await collection.UpdateOneAsync(filter1 & filter2, update,
options: new UpdateOptions { ArrayFilters = arrayFilters });
Note:
This statement is used to convert object to BsonDocument.
BsonDocument.Parse(JsonConvert.SerializeObject(object))
can be replaced with
obj.ToBsonDocument()
Output

GraphQL Query syntax error

am using this GraphQl nuget to achieve a general QUery at my system using the following code
if (!string.IsNullOrEmpty(query))
{
var urlDecode = HttpUtility.UrlDecode(query);
var result =
await (_searchRepository.ExecuteQuery(urlDecode.Replace("\t", "").Replace(#"\", string.Empty))).ConfigureAwait(false);
response = Request.CreateResponse(HttpStatusCode.OK,
new GeneralOutput() {HasError = false, Data = result});
}
else
{
response = Request.CreateResponse(HttpStatusCode.OK,
new GeneralOutput() { HasError = true, Data = null , ErrorType = ErrorType.ValidationError , Message = "Empty Query String"});
}
where Execcute query looks like
public async Task<string> ExecuteQuery(string querystring)
{
try
{
var result = await new DocumentExecuter().ExecuteAsync(_ =>
{
_.Schema = new Schema { Query = new ViewerType() };
_.Query = querystring;
}).ConfigureAwait(false);
var json = new DocumentWriter(Formatting.None, null).Write(result);
return json;
}
catch (Exception e)
{
var logInstance = LogManager.GetCurrentClassLogger();
logInstance?.Error(e,
$" {MethodBase.GetCurrentMethod().Name} => {e.Message}{Environment.NewLine}{e.StackTrace}");
return null;
}
}
And main GraqhQL components like this
public class ViewerType : ObjectGraphType
{
public ViewerType()
{
Name = "Viewer";
Field<QueryResult>("MediaSearch",
arguments: new QueryArguments(
new QueryArgument<StringGraphType> { Name = "userTwelveDigits", DefaultValue = null},
new QueryArgument<DateGraphType> { Name = "fromcreationDate", DefaultValue = null },
new QueryArgument<DateGraphType> { Name = "tocreationDate", DefaultValue = null } ,
new QueryArgument<StringGraphType> { Name = "mediaId", DefaultValue = null },
new QueryArgument<IntGraphType> { Name = "versionTypeId", DefaultValue = null },
new QueryArgument<StringGraphType> { Name = "keyword", DefaultValue = null }
),
resolve: context => (new BaseService<MediaQuery_Result>()).Context.MediaQuery(
context.GetArgument<string>("userTwelveDigits"),
context.GetArgument<DateTime?>("fromcreationDate", null),
context.GetArgument<DateTime?>("tocreationDate", null),
context.GetArgument<string>("mediaId"),
context.GetArgument<int?>("versionTypeId", null),
context.GetArgument<string>("keyword")
));
}
}
public class QueryResult : ObjectGraphType<MediaQuery_Result>
{
public QueryResult()
{
Field(m => m.MediaId).Description("The Media Id");
Field(m => m.MediaTitle).Description("The Media Title");
Field(m => m.MediaIdentifier).Description("The Media Identifier");
Field(m => m.MP4Path).Description("The Media mp4 Path");
Field(m => m.DataS3Path).Description("The Media S3 Path");
Field(m => m.InSync.Value).Description("The Media In Sync or not").Name("InSync");
Field(m => m.IsLinked.Value).Description("The media (video) if linked before or not ").Name("IsLinked");
Field(m => m.IsPublished.Value).Description("The Media If is published or not ").Name("IsPublished");
}
}
I used different graphql query strings which doesn't work example
query MediaSearch
{
MediaTitle
MediaIdentifier
}
query MediaSearch(userTwelveDigits:"12345678",fromcreationDate:null,tocreationDate:null,mediaId:null,versionTypeId:null,keyword:null) { MediaTitle MediaIdentifier }
I always get error
"{\"errors\":[{\"message\":\"Syntax Error GraphQL (1:19) Expected $, found Name \\\"userTwelveDigits\\\"\\n1: query MediaSearch(userTwelveDigits:\\\"12345678\\\",fromcreationDate:null,tocreationDate:null,mediaId:null,versionTypeId:null,keyword:null) { MediaTitle MediaIdentifier }\\n ^\\n\"}]}"
Any idea how to fix that
This is a common error, which is using the "Operation name" of GraphQL, which is more like a cosmetic function name, as a query field. Here's a query that gets the data you are asking for:
query MyQueryName {
MediaSearch {
MediaTitle
MediaIdentifier
}
}
And here is how you pass in arguments - they go on the field:
query MyQueryName {
MediaSearch(mediaId: "asdf") {
MediaTitle
MediaIdentifier
}
}
If you want to learn more about GraphQL, I recommend quickly going through the "learn" section on the website, both about queries and schemas: http://graphql.org/learn/
Note that MyQueryName above can be anything, and doesn't affect the result of the query at all. It's just for server-side logging, so that you can easily identify this query.
Edit - I've written up a blog post about all the different parts of a query, inspired by this question! https://dev-blog.apollodata.com/the-anatomy-of-a-graphql-query-6dffa9e9e747#.lf93twh8x

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"}}}])

C# mongoDB wont update array in database

I want to update array in my mongoDB collection. Posting new document works just fine, but it won't update array. Structure of my document is:
var document = new BsonDocument
{
{ "post_title", model.Title },
{ "post_text", model.Text },
{ "post_author", model.Author },
{ "post_picture", model.Picture },
{ "post_comments", new BsonArray() },
};
And my update function is:
[HttpPost]
[Route("api/PostInfo/{Comment}")]
public async Task Post(Comment comment)
{
try {
BsonObjectId oldId = new BsonObjectId(new ObjectId(comment.id.ToString()));
var mongoDbClient = new MongoClient("mongodb://127.0.0.1:27017");
var mongoDbServer = mongoDbClient.GetDatabase("nmbp");
var collection = mongoDbServer.GetCollection<PostInfo>("post");
var filter = Builders<PostInfo>.Filter.Eq(e => e._id, oldId);
var update = Builders<PostInfo>.Update.Push("post_comments", comment.comment);
await collection.FindOneAndUpdateAsync(filter, update);
var test = oldId.GetType();
}
catch
{
}
}
When debugging, i can see that post controller is triggered, and comment values are correct, but when I take a look in database, value of "post_comments" array is empty. No error is thrown in catch block. Am I doing something wrong?
It looks like the problem was in this line:
var filter = Builders<PostInfo>.Filter.Eq(e => e._id, oldId);
The correct one should look like this:
var filter = Builders<PostInfo>.Filter.Eq("_id", oldId);

elasticsearch NEST client, filed with attribute "not_analyzed" still be analyzed when search keywords contains hyphen

I have a class named "IndexModel":
public class IndexModel
{
[ElasticProperty(Index= FieldIndexOption.NotAnalyzed, Store = true)]
public string ModelNumber{ get; set; }
}
following is how i setup the elastic client:
var uri = new Uri("http://localhost:9200");
var config = new ConnectionSettings(uri);
var client = new ElasticClient(config);
client.Map<IndexModel>(m => m.MapFromAttributes());
I can see the mapped result from response:
Request {
"indexmodel": {
"properties": {
"modelNumber": {
"type": "string",
"store": true,
"index": "not_analyzed"
},
}
}
}
and i have one index record for this type, the value of "ModelNumber" property is "test-123", and following is my query:
var result = client.Search<IndexModel>(s => s.Query(new TermQuery() { Field = Property.Path<IndexModel>(it => it.ModelNumber), Value = "test-123"}));
here is the final mapped request i got:
Method: POST,
Url: http://localhost:9200/_search,
Request: {
"query": {
"term": {
"modelNumber": {
"value": "test-123"
}
}
}
}
But i can not get the result, if i change the value of "ModelNumber" property to "test123", re-index it, and search it by keywords "test123", then it's works, so i think the analyzer still analyzed the "ModelNumber" property, can someone help me, thanks.
I had the same problem, the solution is first create the index then put the mapping and at last add your data.
Add Type Attribute to your model field
[ElasticProperty(OmitNorms = true, Index = FieldIndexOption.NotAnalyzed)]
var node = new Uri("http://192.168.0.56:9200/");
var settings = new ConnectionSettings(node, defaultIndex: "ticket");
var client = new ElasticClient(settings);
var createIndexResult = client.CreateIndex("ticket");
var mapResult = client.Map<TicketElastic>(c => c.MapFromAttributes().IgnoreConflicts().Type("TicketElastic").Indices("ticket"));

Categories