What's with this weird error in the .Net CosmosDb SDK? - c#

I am attempting to run a very simple query against my Azure CosmosDb instance. Here is the query:
var query = container.GetItemQueryIterator<string>(new QueryDefinition("SELECT c.id FROM c"));
while (query.HasMoreResults)
{
var feed = query.ReadNextAsync().Result;
var ids = feed.Select(x => x);
foreach(var id in ids)
{
idsInDatabase.Add(id);
}
}
return idsInDatabase.ToArray();
But when it executes, I get an error stating that there is an "Unexpected character" in line 1, position 2, as seen below:
It's like it is trying to parse JSON instead of my SQL query. This example seems to follow the examples I've seen online. What am I missing here?

The result of that query is a JSON that contains an "id" property, not a string, you are not using VALUE.
Have you tried with a Type like:
public class MyResult
{
public string id { get; set; }
}
var query = container.GetItemQueryIterator<MyResult>(new QueryDefinition("SELECT c.id FROM c"));
while (query.HasMoreResults)
{
var feed = query.ReadNextAsync().Result;
foreach(MyResult result in feed)
{
idsInDatabase.Add(result.id);
}
}
return idsInDatabase.ToArray();

Related

Mongodb C# driver throwing Element Name '_t' is not valid on UpdateOneAsync

I am getting MongoDb.Bson.SerializationException: 'Element name '_t' is not valid.
I read all posts online that appear to be similar issue at first, however, in those posts, element name is specified, here, i am only getting '_t' even by trying different class objects.
var database = AppConfig.client.GetDatabase("test");
var collection = database.GetCollection<BsonDocument>("testcollection");
var filter = Builders<Student>.Filter.Eq(g => g.Name, "oldName");
var update = Builders<Student>.Update.Set(g => g.Name, "NewName");
var updateResult = await collection.UpdateOneAsync(filter.ToBsonDocument(), update.ToBsonDocument());
Also, for all examples i have seen online for UpdateOneAsync function, filter and update below do NOT need to be BSON documents, however, my code won't compile unless I do .ToBSONDocument() as above.
var updateResult = await collection.UpdateOneAsync(filter, update);
My class is minimal:
public class Student
{
[BsonElement("Name")]
public string Name { get; set; }
[BsonElement("Age")]
public int Age { get; set; }
}
Can someone please help figure out what is wrong with above?
Update: How to use render for Update.Set
var registry = BsonSerializer.SerializerRegistry;
var serializer = registry.GetSerializer<Student>();
var filter = Builders<Student>.Filter.Eq(g=> g.Name, "NewName").Render(serializer, registry);
//I think update syntax is not correct.
var update = Builders<Student>.Update.Set(g => g.Name, "Changed").Render(serializer, registry);
//update is throwing error:cannot convert from Mongodb.bson.bsonvalue to mongodb.Driver.updatedefinition<MongoDB.Bson.BsonDocument
var updateResult = await collection.UpdateOneAsync(filter, update);
it's impossible to use ToBsonDocument as you did. The easiest fix is using not typed builders:
var filter = Builders<BsonDocument>.Filter.Eq("name", "oldName");
If you want to use typed builder, you should call Render as below:
var registry = BsonSerializer.SerializerRegistry;
var serializer = registry.GetSerializer<Student>();
var filter = Builders<Student>.Filter.Eq(e=>e.Name, "oldName").Render(serializer, registry);

Mongodb Bson type to Json

I am testing my asp.net core 2.2 web api with Postman. I write the JSON manually like this (httppatch):
{
"query": "{\"name\": \"foo\"}",
"update": [ "{\"$set\":{\"name\":\"foo2\"}}","{\"$set\":{\"path\": \"foo2 path\"}}" ]
}
Now I am thinking how can I build the patch body on the client side.
My question is how can I get the equivalent of this code in json to make it look like the one I write manually?
var query = Builders<T>.Filter.Eq(e => e.name, "foo");
var updates = Builders<T>.Update.Set(e => e.name, "foo2").Set(e => e.Path, "foo2 path");
I guess it's all about serialization, any idea how can I make it?
--Update--
I found this:
var serializerRegistry = BsonSerializer.SerializerRegistry;
var documentSerializer = serializerRegistry.GetSerializer<T>();
var upList = updates.Render(documentSerializer, serializerRegistry);
but it grabs only the last set it combines all sets in one (My bad, thanks to #Simon Mourier to pointing out my mistake !)
Here's the solution:
On the client side
// serializer
var serializerRegistry = BsonSerializer.SerializerRegistry;
var documentSerializer = serializerRegistry.GetSerializer<T>();
// filter and update
var filter = Builders<T>.Filter.Eq(e => e.Level, 2);
var updates = Builders<T>.Update
.Set(e => e.Name, "foo2")
.Set(e => e.Path, "foo2 path")
.Inc(e => e.Level, 1);
// get the string of the filter and the update
var filterString = filter.Render(documentSerializer, serializerRegistry);
var updateString = updates.Render(documentSerializer, serializerRegistry);
// instantiate patch object with properties to json
Patch patch = new Patch()
{
Query = filterString.ToJson(),
Update = updateString.ToJson()
};
// patch object to json
var patchJson = patch.ToJson();
On the server side
[HttpPatch]
public async Task<IActionResult> PatchOne([FromBody]Patch patch)
{
// don't need to ModelState.isValid, it's done on binding
try
{
var update = BsonDocument.Parse(patch.Update);
var filter = BsonDocument.Parse(patch.Query);
var result = await _serviceBase.UpdateOneAsync(filter, update);
...
}
catch (System.Exception ex)
{
return StatusCode(StatusCodes.Status500InternalServerError, ex.Message.ToJson());
}
}
Global Modals (my solution structure)
public class Patch
{
[Required]
public string Query { get; set; }
[Required]
public string Update { get; set; }
}
Thanks for your help !!
I Find a way to see the query
you need make the query and save it in var
var query = Builders<T>.Filter.Eq(e => e.name, "foo");
var makeQuery = _collection.Find(query).ToString();
makeQuery have the value of Filter.Eq

Search a Json object array- List vs Dictionary

I deserialized a JsonResponse using the below code.
var data = (JObject)JsonConvert.DeserializeObject(jsonResponse);
I got the response string which looks something like this
{
"results":[
{
"url":"tickets/2063.json",
"id":20794,
"subject":"Device not working",
"created_date": "2018-01-10T13:03:23Z",
"custom-fields":[
{
"id":25181002,
"value":34534
},
{
"id":2518164,
"value":252344
}
]
}
]
}
My objective is to read certain fields in this array of json objects and insert into a database. The fields i require are id, subject, created_date, member_id.
The member id is part of the custom fields. member_id is the value where id=2518164. I've used List to store this, can you let me know if List or Dictionary is better for this case. How to implement a dictionary
var data = (JObject)JsonConvert.DeserializeObject(jsonResponse);
var tickets = data["results"].ToList();
foreach (var ticketItem in tickets){
Int64? ticketFormId = ticketItem["id"].Value<Int64>();
string subject = ticketItem["subject"].Value<string>();
DateTime createdDate = ticketItem["created_date"].Value<DateTime>();
//Do you think for the next step a dictionary is better or a List is better, since I want to search for a particular id=2518164
var fieldsList = ticketItem["fields"].ToList();
foreach(var fieldItem in fieldList){
Int64? fieldId = fieldItem["id"].Value<Int64>();
if(fieldId!=null && fieldId == 2518164){
memberId = fieldItem["value"].Value<string>();
}
}
}
If you're next step to insert them all into the database, just store them into a list. A dictionary is only useful to search the item by a key.
You can also use linq to process the json in a simpler way:
var tickets = JObject.Parse(jsonResponse)["results"]
.Select(ticket => new
{
Id = (long)ticket["id"],
Subject = (string)ticket["subject"],
CreatedDate = (DateTime)ticket["created_date"],
MemberId = (long)ticket["custom-fields"]
.FirstOrDefault(cf => (int)cf["id"] == 2518164)
?["value"],
})
.ToList();

How do I nest this LINQ query?

I have an XML document from a web service that I am trying to query. However, I am not sure how to query the XML when it has elements nested inside other elements.
Here is a section of the XML file (I haven't included all of it because it's a long file):
<response>
<display_location>
<full>London, United Kingdom</full>
<city>London</city>
<state/>
<state_name>United Kingdom</state_name>
<country>UK</country>
<country_iso3166>GB</country_iso3166>
<zip>00000</zip>
<magic>553</magic>
<wmo>03772</wmo>
<latitude>51.47999954</latitude>
<longitude>-0.44999999</longitude>
<elevation>24.00000000</elevation>
</display_location>
<observation_location>
<full>London,</full>
<city>London</city>
<state/>
<country>UK</country>
<country_iso3166>GB</country_iso3166>
<latitude>51.47750092</latitude>
<longitude>-0.46138901</longitude>
<elevation>79 ft</elevation>
</observation_location>
I can query "one section at a time" but I'm constructing an object from the LINQ. For example:
var data = from i in weatherResponse.Descendants("display_location")
select new Forecast
{
DisplayFullName = i.Element("full").Value
};
var data = from i in weatherResponse.Descendants("observation_location")
select new Forecast
{
ObservationFullName = i.Element("full").Value
};
And my "Forecast" class is basically just full of properties like this:
class Forecast
{
public string DisplayFullName { get; set; };
public string ObservationFullName { get; set; };
//Lots of other properties that will be set from the XML
}
However, I need to "combine" all of the LINQ together so that I can set all the properties of the object. I have read about nested LINQ but I do not know how to apply it to this particular case.
Question: How do I go about "nesting/combining" the LINQ so that I can read the XML and then set the appropriate properties with said XML?
One possible way :
var data = from i in weatherResponse.Descendants("response")
select new Forecast
{
DisplayFullName = (string)i.Element("display_location").Element("full"),
ObservationFullName = (string)i.Element("observation_location").Element("full")
};
Another way ... I prefer using the Linq extension methods in fluent style
var results = weatherResponse.Descendants()
.SelectMany(d => d.Elements())
.Where(e => e.Name == "display_location" || e.Name == "observation_location")
.Select(e =>
{
if(e.Name == "display_location")
{
return new ForeCast{ DisplayFullName = e.Element("full").Value };
}
else if(e.Name == "observation_location")
{
return new ForeCast{ ObservationFullName = e.Element("full").Value };
}
else
{
return null;
}
});

how to return IEnumerable<String> with linq. Getting Subquery returned more than 1 value

I want the query to give me back a NotificationConfiguration and also an IEnumerable<string> (which I will later transform to a single string using SB). Once the query gives me back those two items I will transform it using a constructor in my view model so I can properly display all the data using a DataTable. The answer I am looking for maybe very specific but I need to understand why I'm getting the subquery error when I want it to return an IEnumerable<string> and how to fix it. Also please note... according to the .net docs the code should be handing my back an IEnumerable<string> but for some reason its still crashing. Here is the relevant code samples again:
[HttpPost]
public ActionResult Index(DataTableRequest requestedData)
{
using (this.dataStore.Session.BeginTransaction())
{
return this.dataStore.Query<NotificationConfiguration>()
.TableRange(requestedData, p => new NotificationConfigurationViewModel(p, p.Events.Select(x => x.Code) ?? null));
}
}
.
public NotificationConfigurationViewModel(NotificationConfiguration notification , IEnumerable<string> events)
{
Contract.Requires(notification != null);
this.notification = notification;
this.events = events;
}
.
[Display(Name = "Events")]
public virtual string EventTypeCodes
{
get
{
var codes = new StringBuilder();
foreach (var item in this.events)
{
codes.Append(item + ",");
}
return codes.ToString().TrimEnd(',');
}
}

Categories