Hi,
I'm trying to insert a JSON object into LiteDB.
Let's say I have a class:
public class Packet
{
public ObjectId Id { get; set; }
public long SeqNumber { get; set; }
...
public BsonDocument doc { get; set; } // I want my json here, so it probably should be BsonDocument
};
So far I tried to create a BsonDocument using JsonSerializer.Deserialize(jsonString);
It didn't work, I got exception "Value was either too large or too small for an Int32.", probably because I have few Int64 there.
I can parse the json with Newtonsoft json.net, but could not figure out how to convert JObject to BsonDocument. I read something about onmodelcreating, but have no idea how to implement that.
Can someone help me with this please?
Thanks,
Alex
Hi @alexchern, LiteDB has a different way to represent non-default data types in JSON (it麓s extended json). Its similiar to MongoDB, and you can see here:
https://github.com/mbdavid/LiteDB/wiki/Data-Structure#json-extended
@alexchern if you need a quick-dirty-recursive hack, then this might (or might not) work:
```c#
Dictionary
{
var dict = token.ToObject
foreach(var item in dict.Where(x => x.Value.IsNull).ToList())
{
dict[item.Key] = new BsonValue(ToDictionary(token[item.Key]));
}
return dict;
}
Just pass the result of JObject.Parse() to this method and it should do the trick:
```c#
var jobject = JObject.Parse(json);
var bson = new BsonDocument(ToDictionary(jobject));
Thanks a lot, in general it worked, though it replaced all the integers (not only longs). Is there any easy way to get (convert to) an "original" (not extended) json back after serialization?
Thanks,
Alex
@alexchern continuing the theme of dirty, hacky solutions, you can use the following code to get regular json from BsonDocument:
c#
string json = bson.ToString(); // the same object from my previous snippet
var regex = new Regex(@"\{""\$(?<type>\w+)""\s*:\s*""(?<value>.+?)""\}");
var matches = regex.Matches(json);
var nonQuotable = new[] { "numberLong", "numberDecimal", "minValue", "maxValue" };
foreach(Match match in matches)
{
string type = match.Groups["type"].Value;
string value = match.Groups["value"].Value;
json = json.Replace(match.Value, nonQuotable.Contains(type) ? value : $@"""{value}""");
}
I'd like to stress that regular expressions aren't the best in terms of performance and make the code less human-friendly. I'd also like to recommend using a proper strong-typed model to store the json (if that's feasible for you, of course) or, if you don't mind using up additional space, storing the original json string along with its bson counterpart (aka the easiest solution of all).
@mach37 You mean PR to this repo? The author is doing a good job keeping this library dependency-free, so I think I'd get a slap on the wrist if I tried to add one just to do this one conversion 馃槈
Hi Velorien,
Once again, thanks for your help.
Though I ended up doing exactly what you mentioned at the end - storing original json as a string (at the expense of additional space), the above solution is very useful. I'll definitely give it a try. Using a strong typed model is not an option for me as the data is dynamic, so I'm using your method to store the data in a way I could query it and keep an original, to have it easily available when I need it.
Thanks,
Alex
@alexchern Glad to be of help :)
Most helpful comment
@alexchern if you need a quick-dirty-recursive hack, then this might (or might not) work: ToDictionary(JToken token)>();
```c#
Dictionary
{
var dict = token.ToObject
foreach(var item in dict.Where(x => x.Value.IsNull).ToList())
{
dict[item.Key] = new BsonValue(ToDictionary(token[item.Key]));
}
}