InsertMany json in string MongoDB - c#

I would like to get collection via string and insert many json via string. How to do it? I don`t want to prepare object via C# class because my schema will change all the time and this is easy way.
code
const string connectionString = "mongodb://user:password#localhost:27017/myDB";
var client = new MongoClient(connectionString);
var db = client.GetDatabase("myDB");
var col = db.GetCollection("mycollection")
string insert = "[("Element1":"Test"),("Element2":"Test")]";
col.insertMany(insert);
my assemblies
MongoDB.Bson
MongoDB.Driver
MongoDB.Driver.Core
MongoDB.Libmongocrypt

ok. I found solution
public static async Task SaveToCollation(IMongoDatabase database, string collectionName, string json)
{
var collection = database.GetCollection<BsonDocument>(collectionName);
await collection.InsertOneAsync(BsonDocument.Parse(json));
}

Related

how to store stringify json data into mongodb using C# MongoDB.Driver

i am fetching data in strigify json format
"[{\"ApplytoAllYesNo\":\"\",\"PartNumber\":\"\",\"Description\":\"\",\"LotNumber\":\"\",\"Revision\":\"\",\"Comment\":\"\",\"QualStatus\":\"\",\"Upload\":\"\",\"buildID\":\"62161d4fee3776fba3d8b83e\"},{\"ApplytoAllYesNo\":\"\",\"PartNumber\":\"\",\"Description\":\"\",\"LotNumber\":\"\",\"Revision\":\"\",\"Comment\":\"\",\"QualStatus\":\"\",\"Upload\":\"\",\"buildID\":\"62161d4fee3776fba3d8b83e\"},{\"ApplytoAllYesNo\":\"\",\"PartNumber\":\"\",\"Description\":\"\",\"LotNumber\":\"\",\"Revision\":\"\",\"Comment\":\"\",\"QualStatus\":\"\",\"Upload\":\"\",\"buildID\":\"62161d4fee3776fba3d8b83e\"},{\"ApplytoAllYesNo\":\"\",\"PartNumber\":\"\",\"Description\":\"\",\"LotNumber\":\"\",\"Revision\":\"\",\"Comment\":\"\",\"QualStatus\":\"\",\"Upload\":\"\",\"buildID\":\"62161d4fee3776fba3d8b83e\"},{\"ApplytoAllYesNo\":\"\",\"PartNumber\":\"\",\"Description\":\"\",\"LotNumber\":\"\",\"Revision\":\"\",\"Comment\":\"\",\"QualStatus\":\"\",\"Upload\":\"\",\"buildID\":\"62161d4fee3776fba3d8b83e\"}]"
every time this data will change, that's why I am unable to use fixed model hear as my object won't have fixed number of columns, and number columns will change in each request, these columns created in front end.
I just want to insert json strigify data into mongoDB whatever it comes in that object.
[HttpPost("saveBuildData")]
public async void saveBuildData(BuildSchema data)
{
await _buildsService.insertBuildConfigData(data.buildData);
}
public async Task insertBuildConfigData(dynamic obj)
{
var connectionString = _configuration["DatabaseSettings:ConnectionString"];
var client = new MongoClient(connectionString);
var database = client.GetDatabase("cascade");
var collection = database.GetCollection<BsonDocument>("buildconfig_MATERIAL");
var q = BsonSerializer.Deserialize<BsonDocument>(obj);
await collection.InsertOneAsync(q);
}
above code is not working and I am unable to insert the data into mongoDB.
enter image description here
This might help someone looking for a solution to this problem. It worked for me when I changed
collection.InsertOne(q)
instead of
await collection.InsertOneAsync(q);
I am not claiming this is the best solution but it worked in my case, where I am only interested in uploading a json file to Mongodb collection using c#.

System.Text.Json.JsonException: The JSON value could not be converted

I'm using Ubuntu and dotnet 3.1, running vscode's c# extension.
I need to create a List from a JSON file, my controller will do some calculations with this model List that I will pass to it
So, here is my code and the error I'm getting.
First, I thought my error was because at model my attributes were char and C#, for what I saw, cannot interpret double-quotes for char, it should be single quotes. Before losing time removing it, I just changed my type declarations to strings and it's the same error.
Can someone help me?
ElevadorModel
using System.Collections.Generic;
namespace Bla
{
public class ElevadorModel
{
public int andar { get; set; }
public string elevador { get; set; }
public string turno { get; set; }
}
}
Program.cs:
class Program
{
static void Main(string[] args)
{
var path = "../input.json";
string jsonString;
ElevadorModel elevadoresModel = new ElevadorModel();
jsonString = File.ReadAllText(path); //GetType().Name = String
Console.WriteLine(jsonString); //WORKS
elevadoresModel = JsonSerializer.Deserialize<ElevadorModel>(jsonString);
}
JSON:
Your input json has an array as the base token, whereas you're expecting an object. You need to change your deserialization to an array of objects.
var elevadoresModels = JsonSerializer.Deserialize<List<ElevadorModel>>(jsonString);
elevadoresModel = elavoresModels.First();
Your input JSON is an array of models, however you're trying to deserialize it to a single model.
var models = JsonSerializer.Deserialize<List<ElevadorModel>>(jsonString);
This is also a problem in Blazor-Client side. For those calling a single object
e.g ClassName = await Http.GetFromJsonAsync<ClassName>($"api/ClassName/{id}");
This will fail to Deserialize. Using the same System.Text.Json it can be done by:
List<ClassName> ListName = await Http.GetFromJsonAsync<List<ClassName>>($"api/ClassName/{id}");
You can use an array or a list. For some reason System.Text.Json, does not give errors and it is successfully able Deserialize.
To access your object, knowing that it is a single object use:
ListName[0].Property
In your case the latter solution is fine but with the path as the input.
In my case, I was pulling the JSON data to deserialize out of an HTTP response body. It looked like this:
var resp = await _client.GetAsync($"{endpoint}");
var respBody = await resp.Content.ReadAsStringAsync();
var listOfInstances = JsonSerializer.Deserialize<List<modelType>>(respBody);
And the error would show up. Upon further investigation, I found the respBody string had the JSON base object (an array) wrapped in double quotes...something like this:
"[{\"prop\":\"value\"},...]"
So I added
respBody = respBody.Trim('\"');
And the error changed! Now it was pointing to an invalid character '\'.
I changed that line to include
respBody = respBody.Trim('\"').Replace("\\", "");
and it began to deserialize perfectly.
For reference:
var resp = await _client.GetAsync($"{endpoint}");
var respBody = await resp.Content.ReadAsStringAsync();
respBody = respBody.Trim('\"').Replace("\\", "");
var listOfInstances = JsonSerializer.Deserialize<List<modelType>>(respBody);

Retrieving Chat Bot conversation data in Azure

A brief background first: The Bot framework stores the conversation data within a storage either Azure tables/Cosmos DB (Azure tables in my case). For each conversation there is an entry made into the Azure table with the timestamp, userid, conversation messages and other details.
I am trying to retrieve the conversation details from Azure table storage using custom code in C# as shown below.
Microsoft.WindowsAzure.Storage.CloudStorageAccount storageAccount = Microsoft.WindowsAzure.Storage.CloudStorageAccount.Parse(connectionString);
Microsoft.WindowsAzure.Storage.Table.CloudTableClient tableClient = storageAccount.CreateCloudTableClient();
CloudTable table = tableClient.GetTableReference("botdata");
TableQuery<DynamicTableEntity> projectionQuery = new TableQuery<DynamicTableEntity>().Where(TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, "directline:user"));
var dataRow = table.ExecuteQuery(projectionQuery).Where(q => q.RowKey == "souvik").FirstOrDefault();
var conversation = Encoding.UTF8.GetString(dataRow.Properties["Data"].BinaryValue);
Console.WriteLine(conversation);
I am getting some gibberish text, something like this- \u001f�\b\0\0\0\0\0\u0004\0��\u0005\0C���\u0002\0\0\0 when I retrieve the data stored in Binary format in the Azure table storage. The data looks something like as shown below in the Azure storage explorer-
I have tried and tested for each conversation and I have seen that each time I type and send a data to the bot and get a response, new records are getting added to the Azure table with correct timestamp. Is it the correct way of retrieving the data or am I doing something wrong? Let me know if I can add more details.
Update-1:
I have referred this- How to retrieve Saved Conversation Data in Azure (Tablelogger) but did not get much help my issue.
Update-2
Based on Fei's answer below, I just noticed when I use the PartitionKey as directline:user or directline:conversation I get the deserialized values as {} but if I use directline:private I get somthing like this-
{"ResumptionContext":{"locale":"en-US","isTrustedServiceUrl":true},
"DialogState":"H4sIAAAAAAAEAO1a328iVRRmYGYKbTfbdZtNzLq7GM26DWS2FGi7MVUptUrcVi1VYxrSvcCFjh1mmrl3quyjb74YEx+N/hW+uzFxE/8KX9fsH6HnzAxQ7A8GhHpZoemBDs
O953znO+d+99KQFAqF/oIHPuNjNgzm8y29YlvMqnFt3YJfRzeq1E7GP6U20y1zLa2llrQlLZOM5x2DOzZdM6nDbWIk4x85ZUOvfECbu9YhhTtT5Vp6NbtMqunlDE1nFZznF+nM8bWCyaltEoNpm
3oZpvKeHqX29s6+f0MnhlVnJz7nXdkl7DAZH1kMpVIEglAYJ5VDtWaTBmXKl0TnLCLLT8LFJuO0oeUtw6AVDjMx7T1qUluvaA91xs+P5lT0hU0cW8DwRzo4CYhOESAlhv6YIMaJIrdsWjAhJ2aF
rjd3m0e06Ni2VSecJj4sfwGp2KE1alN4Gxl+ObPgbwzJEpPRKGBk/HPCkmFUoLqvA4ZM2Wf6YxrdP/aGBaR/DdpfhMVur4TUiUZjqs8i5I8iXwpxsUPLeEfkjs/ST0ydN7sGfN/CWV16T4GRFN
/FWBTMFDodkvxL8pOxz4YbZwzNNJgrYRlj7gUOMlTeIJzE3DsQ0NkcY7RRNprbEKcUkqLqDNz0NPBqiPBskgrksikgSphsdXak6kFy6YXzXAHzW1DgPoPFWWzcYoibEutLGwlcLHKD2Icyai
JZvpyV9odwH1x4tCQaask9v5t4oSXjDVaxbEMvd0bPaIv403vw8soKyVayy6kH6QxdXH3gpcTtYVfRzGFzxkbmdrRraF7CS1dbPfw6cnFuAmpvUGWbMi6blFZlOTBYO/CZ/yNYiYD4bAOcbcb
OIxefw/60n0+j9Jg6JoZD9/dD0bAvRhSk+tNxp3T32HnLNCkubFphizJG6jQHu4lj0Bv/9KJ95xC7/An2B8ZVVPYLhOtAhXIDWf4nFMpz/zBHwqZ+rf3Ws5NvXW/JqJdDfeyWth3DcMtCPNHR
0VDz/axbopJxlK3Y3Zdw0FMqJ3adcrVB+YFVjcg9t3s/nUOUi3BK7B445iHg7HhiddSLzH1/AhCH/sGKtgVbLmoXzJp13hb2JppX0NxCCt3oZ50QlUKC9LPB2fb7ENgmCAgDE/M2mjto4ti2b
7ba9quTJndxK+isB1jWojcuXJNV251K/qaHr55HuRr3vhi5lG3ja1jEtwYgMZJVxsOurpOvWN4gjLmvinrdJOjWdPvV0rQ3JG755/wz8Zxdh6BNziR8hCLRK74jeNNeSX0d50GeuzlX745BztU
3wMmvI604DmxKqrpZ19AP5lrwIOjBqa/K+o+4VIojbPcCn9D6X8gNMNM5zWSQBnSGYwVAEfzqyhhMeQrePJ4nGYbLUTc1C+o9SMQz5eJE9JsJwZrtaL+LGYxCYwLRcPk50pYSiO54gj4t3W4piY
WJ1h2azOuIDpRsL5B+PalPfu5PnwgSQVvKJFBHo5hGOaMmu3WD9mKlTb0P8fw4kRjDbeFBkxtQfSxCjr5XJ+pjoj4uQX0I0piCCxUFt54CbYkHP876tkcQ+QOim4mHlnXkXRH2sDSFZglNGsxsBs
zax2YOYur4lQrql+kYhoJr8njKisHpcLfbryJpHBlU83DUdiyLe4FnBs1SFs0ymhVUPKmW3l8Vq546khkZJVqNoO6dzkE3rdAqNbncR9LCLfyldEtsvglmxseWNc2KpznXBIxbfQuc+k66QJTET8
RxztrbXrm8F1B5nH7Fe65zOfyvIVI26KnTnAX1bXDrj//erZFi72/Qs62CfWdsm2OntrEOAtYO3BnC+pFWWmWzDmbe93wHKlE/plU3wWr+Xy896kZwz9R33UxcxL6zvBwdDQNvRBbUTdxkhMVxXRSKesU28zeNVmRMBTMAAA=="}
I have a feeling that the DialogState data in the JSON above needs to be decrypted?
For every message I type and the response I receive, there are three records inserted into the Azure table each with a different PartitionKey which are- directline:private, directline:user and directline:conversation.
Binary data in Azure Table Storage is stored as Base64 encoded string. What you would need to do is convert this string to bytes first and then get the string from those bytes.
Something like:
var conversation = Encoding.UTF8.GetString(Convert.FromBase64String(dataRow.Properties["Data"].BinaryValue));
If you’d like to use WindowsAzure.Storage client library to retrieve entities from table storage and extract data from Data property, you can refer to the following code.
CloudStorageAccount storageAccount = CloudStorageAccount.Parse("DefaultEndpointsProtocol=https;AccountName={your_account_name};AccountKey={your_account_key};EndpointSuffix=core.windows.net");
CloudTableClient tableClient = storageAccount.CreateCloudTableClient();
CloudTable table = tableClient.GetTableReference("botdata");
TableQuery<MessageEntity> query = new TableQuery<MessageEntity>().Where(TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, "emulator:user"));
foreach (MessageEntity entity in table.ExecuteQuery(query))
{
string mydata = "";
using (var msi = new MemoryStream(entity.Data))
using (var mso = new MemoryStream())
{
using (var gs = new GZipStream(msi, CompressionMode.Decompress))
{
gs.CopyTo(mso);
}
mydata = Encoding.UTF8.GetString(mso.ToArray());
}
object data = JsonConvert.DeserializeObject(mydata);
//.....
}
MessageEntity:
public class MessageEntity : TableEntity
{
public MessageEntity(string pk, string rk)
{
this.PartitionKey = pk;
this.RowKey = rk;
}
public MessageEntity() { }
public string BotId { get; set; }
public string ChannelId { get; set; }
public string ConversationId { get; set; }
public byte[] Data { get; set; }
public string UserId { get; set; }
}
Test result:
Note:
In source code, you can find the Data property defined as byte[] in the BotDataEntity class.
In Jason Sowers's reply, he has shared the information about serialize and deserialize of the Data property.
I am assuming you are using the botbuilder-azure package
don't do this in a dialog because you can just access the same data in the context object. it just happens to be where I wrote the code
It's actually as simple as this:
private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<object> result)
{
var activity = await result as Activity;
IBotDataStore<BotData> table = new TableBotDataStore(ConfigurationManager.ConnectionStrings["StorageConnectionString"].ConnectionString);
//use the type of state data you need
var userData = await table.LoadAsync(Address.FromActivity(activity), BotStoreType.BotUserData, CancellationToken.None );
var privateConvoData = await table.LoadAsync(Address.FromActivity(activity), BotStoreType.BotPrivateConversationData, CancellationToken.None );
var convoData = await table.LoadAsync(Address.FromActivity(activity), BotStoreType.BotConversationData, CancellationToken.None);
//in this case I am just replying with the data, but do what you need with it here
var reply = activity.CreateReply(userData.Data.ToString());
var reply2 = activity.CreateReply(privateConvoData.Data.ToString());
var reply3 = activity.CreateReply(convoData.Data.ToString());
await context.PostAsync(reply);
await context.PostAsync(reply2);
await context.PostAsync(reply3);
context.Wait(MessageReceivedAsync);
}
If you notice in the source for botbuilder-azure there is a serialize and deserialize method. Where this happens:
private byte[] Serialize(object data)
{
using (var cmpStream = new MemoryStream())
using (var stream = new GZipStream(cmpStream, CompressionMode.Compress))
using (var streamWriter = new StreamWriter(stream))
{
var serializedJSon = JsonConvert.SerializeObject(data, serializationSettings);
streamWriter.Write(serializedJSon);
streamWriter.Close();
stream.Close();
return cmpStream.ToArray();
}
}
So the data you need is compressed into the "jibberish" you were seeing. When accessing the data via the LoadAsync method it is also being decompressed like here:
private object Deserialize(byte[] bytes)
{
using (var stream = new MemoryStream(bytes))
using (var gz = new GZipStream(stream, CompressionMode.Decompress))
using (var streamReader = new StreamReader(gz))
{
return JsonConvert.DeserializeObject(streamReader.ReadToEnd());
}
}
deserialize is called inside the LoadAsync method in the return statement return new BotData(entity.ETag, entity.GetData()); It its the GetData() method like below:
internal ObjectT GetData<ObjectT>()
{
return ((JObject)Deserialize(this.Data)).ToObject<ObjectT>();
}

Using Json to Create FormDialog

I am trying to build user and conversation specific dialogs using json schema and I have the LINQ queries generating the json perfectly. If I save a sample of the json to disk and use it like the annotatedsandwich example where it is read from a file on disk, it works great. The json is unique per user and conversation and instead of writing to disk I want to use it in memory. I do not see how to pass the json string to the BuildJsonForm method or alternately how to get the userID information in the BuildJsonForm method in order to generate the json based on the user and conversation. I know I am missing something that will let me do this but I am not finding it. Any assistance with how this should be done would be appreciated. Thank you.
Instead of doing (using the AnnotatedSandwich code)
FormDialog.FromForm(SandwichOrder.BuildJsonForm)
You could just build the BuildFormDelegate and pass your parameters:
string schema = "your jsonform schema";
BuildFormDelegate<JObject> formDelegate = () => SandwichOrder.BuildJsonForm(schema);
FormDialog.FromForm(formDelegate)
Create a custom form builder to which you pass your custom form json schema
[Serializable]
public class CustomFormBuilder
{
public string FormJson { get; set; }
public CustomFormBuilder(string formJson)
{
FormJson = formJson;
}
public IForm<JObject> BuildJsonForm()
{
var schema = JObject.Parse(FormJson);
var form = new FormBuilderJson(schema)
.AddRemainingFields()
.Build();
return form;
}
}
Use as follows (where formJson is your user specific form)
var formBuilder = new CustomFormBuilder(formJson);
var jsonFormDialog = FormDialog.FromForm(
formBuilder.BuildJsonForm,
FormOptions.PromptInStart);
This will avoid the ClosureCaptureExcept‌​ion.

storing JSON data in db

I'm trying to store data from fb wall into database.
My *.cs code
public ActionResult GetWall()
{
JSONObject wallData = helper.Get("/me/feed");
if (wallData != null)
{
var data = wallData.Dictionary["data"];
List<JSONObject> wallPosts = data.Array.ToList<JSONObject>();
ViewData["Wall"] = wallPosts;
}
return View("Index");
}
Which gets posts from fb wall.
And then I have an *.aspx file, which "breaks" my wallposts into pieces (objects) or whatever you like to call them.
foreach (Facebook.JSONObject wallItem in wallPosts)
{
string wallItemType = wallItem.Dictionary["type"].String;
//AND SO ON...
What i'm trying to say is that I can access to elements inside fb JSON.
Is there a way i can access to the JSON elements inside *.cs file.
Or is there a way I can store elements inside the *.aspx file to db?
And if its possible, I would like to know how. =)
Thanks for help
Don't use the SDK. Fetch the JSON Data using HttpWebRequest and then Deserialize it using System.Runtime.Serialization.Json.DataContractJsonSerializer. You just have to Create a class with same properties returned in JSON data. See the example below
string Response = Utilities.HttpUtility.Fetch("https://graph.facebook.com/me?access_token=" + AccessToken, "GET", string.Empty);
using (System.IO.MemoryStream oStream = new System.IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes(Response)))
{
oStream.Position = 0;
return (Models.FacebookUser)new System.Runtime.Serialization.Json.DataContractJsonSerializer(typeof(Models.FacebookUser)).ReadObject(oStream);
}
I'm not familiar with the facebook API and the question isn't too clear, but I assume that the string wallItemType is itself a JSON string, and you wish to parse it.
I'd use the Json.Net library to parse this.
using Newtonsoft.Json;
//your code as above
foreach (Facebook.JSONObject wallItem in wallPosts)
{
string wallItemType = wallItem.Dictionary["type"].String;
//I assume wallItemType is a JSON string {"name":"foobar"} or similar
JObject o = JObject.Parse(wallItemType);
string name = (string)o["name"]; //returns 'foobar'
//and so on
you can also use the Json.Net to deserialize to a custom type. This custom type could be mapped to a SQL database using NHibernate.
If you wish to store the entire json string in a database, then you could use a document database such as CouchDB.

Categories

Resources