Why mongodb store binary data in the form of base64? - mongodb

I'm trying to learn how mongodb store each and every data type under the hood.
I have found it stores data in BSON format.
In order to store binary data in mongodb, it requires users to convert byte array in base64 then pass that base64 converted string to BinData(subtype,content in base64) class.
What is the reason behind storing binary data in this format. Why mongodb doesn't allow us to store raw binary?

According to the BSON specification, binary is stored as a 32-bit length followed by a type identifier and then by a series of bytes. Not a base64 string, bytes.
A shamelessly copied function from codementor.io shows that in languages that have the capability to handle binary data directly, it can be directly stored:
public class Question
{
[BsonId]
[BsonRepresentation(BsonType.ObjectId)]
public string Id { get; set; }
public string Category { get; set; }
public string Type { get; set; }
public string QuestionHeading { get; set; }
public byte[] ContentImage { get; set; }
public decimal Score { get; set; }
}
public class QuestionService
{
private readonly IMongoCollection<Question> _questions;
public QuestionService(IDatabaseSettings settings)
{
var client = new MongoClient("<YOUR CONNECTION STRING>");
var database = client.GetDatabase("<YOUR DATABASE NAME>");
_questions = database.GetCollection<Question>("Questions");
}
public Question Get(string id)
{
var result = _questions.Find(
q => q.Id == id).FirstOrDefault();
return result;
}
public Question Create(Question question)
{
_questions.InsertOne(question);
return question;
}
}
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
var service = new QuestionService();
// CONVERT JPG TO A BYTE ARRAY
byte[] binaryContent = File.ReadAllBytes("image.jpg");
var question = new Question
{
Category = "Children's Quizzes",
Type = "Puzzles",
QuestionHeading = "Find the cat in the below image",
ContentImage = binaryContent, // Store the byte array in ContentImage property
Score = 10
};
service.Create(question);
}
BinData() is a constructor that permits specifying binary data directly in the source code text.
geeksforgeeks.org has an example for how to Upload and Retrieve Image on MongoDB using Mongoose

Related

iText 7 Get all text chunks and their location

I'm trying to get all the individual text chucks and their location using iText7. I need to parse the chucks and let a user select specific texted to be parsed from future identical PDFs. I need to have the user select the employee name, ID, and other text. I will then store the location of that data to use in processing future PDFS. The selection/mapping is a one time setup. Here is an example of the data I have returning in iText 5:
X
Y
chunk Text
1.763889
282.9278
11225 North Sourth St, Bedrock, ND, 99780, Ph: 999 321-6543
15.166975
277.17752
Employee ID
67.3675
277.17752
Employee Name
18.458744
272.22098
001159
68.33058
272.22098
Fred Flintstone
The below code works in iText 5 and I'm trying got migrate it to iText 7 for a project. Some of the objects are no longer exposed in iText 7.
void Main()
{
string filename = #"C:\Employee Info.pdf";
using (var reader = new PdfReader(filename))
{
var parser = new PdfReaderContentParser(reader);
var strategy = parser.ProcessContent(1, new LocationTextExtractionStrategyWithPosition());
// work with the locatins on the chucks to provide list to user.
reader.Close();
}
}
public class LocationTextExtractionStrategyWithPosition : LocationTextExtractionStrategy
{
public readonly List<TextChunk> locationalResult = new List<TextChunk>();
private readonly ITextChunkLocationStrategy tclStrat;
public LocationTextExtractionStrategyWithPosition() : this(new TextChunkLocationStrategyDefaultImp())
{
}
public LocationTextExtractionStrategyWithPosition(ITextChunkLocationStrategy strat)
{
tclStrat = strat;
}
public override void RenderText(TextRenderInfo renderInfo)
{
LineSegment segment = renderInfo.GetBaseline();
if (renderInfo.GetRise() != 0)
{ // remove the rise from the baseline - we do this because the text from a super/subscript render operations should probably be considered as part of the baseline of the text the super/sub is relative to
Matrix riseOffsetTransform = new Matrix(0, -renderInfo.GetRise());
segment = segment.TransformBy(riseOffsetTransform);
}
TextChunk tc = new TextChunk(renderInfo.GetText(), tclStrat.CreateLocation(renderInfo, segment));
//tc.Dump();
locationalResult.Add(tc);
}
}
public class TextLocation
{
public float X { get; set; }
public float Y { get; set; }
public string Text { get; set; }
}

Save CodeFirst's property to Base64 string in EFCore but read back X509Certificate2 from EFCore?

The ThirdParty model contain a property Certificate. It is a datatype of X509Certificate2 for source code use, but EFCore doesn't support it, meaning I have to convert it to Base64 string for EFCore database storage. Then convert it back to X509Certificate2 when reading from EFCore database.
How do we instruct EFCore to do this automatically with whatever property mapper?
public class ThirdParty
{
public Guid ThirdPartyId { get; set; }
public X509Certificate2 Certificate { get; set; }
public string RawData { get; set; }
public DateTime CreatedDate { get; set; }
}
var certificate1 = new X509Certificate();
var thirdParty = new ThirdParty() { Certificate = certificate }
var certificate2 = thirdParty.Certificate;
One approach would be to add an additional not mapped property that will return the X509Certificate2 object that will be created out of the Base64 string that was read from database.
Therefore the CertificateString property is used only to save and read from data context and the Certificate property is for usage in your other logic.
public class ThirdParty
{
private X509Certificate2 _certificate;
public Guid ThirdPartyId { get; set; }
// to write in data context only - only set it in production code
public string CertificateString
{
get
{
// return the Base64 string - is just pseudo code
return _certificate?.ToString();
}
set
{
_certificate = new X509Certificate2(value);
}
}
// not mapped for data context - to read from data context only - only read fro
public X509Certificate2 Certificate
{
get
{
if (string.IsNullOrWhiteSpace(CertificateString))
{
return default(X509Certificate2);
}
return new X509Certificate2(CertificateString);
}
private set
{
// will be set by CertificateString
}
}
public string RawData { get; set; }
public DateTime CreatedDate { get; set; }
}
To not map a property you could use [NotMapped] as Data Annotation or .Ignore(p => p.PropertyName) in Fluent API.
I would do something like this, possibly look at Why does Json.NET fail to serialize a X509Certificate2? if you're having issues with serializing the cert.
public class Configuration : IEntityTypeConfiguration<ThirdParty>
{
public void Configure(EntityTypeBuilder<ThirdParty> builder)
{
// This Converter will perform the conversion to and from Json to the desired type
builder.Property(e => e.Certificate).HasConversion(
v => JsonConvert.SerializeObject(v, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }),
v => JsonConvert.DeserializeObject<X509Certificate2>(v, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }));
}
}

Related data not being added for existing parent entity

Im trying to save a rating against a place, I have the code below, but it doesnt seems to save rating (to the ratings table) for an existing entity
place.Ratings.Add(rating);
_placeRepository.AddPlaceIfItDoesntExist(place);
_placeRepository.Save();
This is the repository method
public void AddPlaceIfItDoesntExist(Place place)
{
var placeItem = context.Places.FirstOrDefault(x => x.GooglePlaceId == place.GooglePlaceId);
if(placeItem==null)
{
context.Places.Add(place);
}
else
{
context.Entry(placeItem).State = EntityState.Modified;
}
}
and this is the poco
public class Place
{
public Place()
{
Ratings = new List<Rating>();
}
public int Id { get; set; }
public string Name { get; set; }
public string GooglePlaceId { get; set; }
}
I think the crux of the problem is because i need to check if the place exists based on googleplaceid(a string) rather than the id (both are unique per place btw)
Here
context.Entry(placeItem).State = EntityState.Modified;
you just mark the existing placeItem object as modified. But it's a different instance than the passed place object, hence contains the orginal values.
Instead, replace that line with:
context.Entry(placeItem).CurrentValues.SetValues(place);
Alternatively, you can use the DbSetMigrationsExtensions.AddOrUpdate method overload that allows you to pass a custom identification expression:
using System.Data.Entity.Migrations;
public void AddPlaceIfItDoesntExist(Place place)
{
context.Places.AddOrUpdate(p => p.GooglePlaceId, place);
}

Web API Model binding - Complex Parameter

I have a string received in query string
f[0][p]=zap&f[0][v][] = 110&f[0][v][]=500&f[1][p] = prih&f[1][v][] = 10000000&f[1][v][] = 30000000000
I try to catch it with string[] but it is always null. How to represent this parameter to Web API so it can serialize it?
I have a workaround with reading it for Uri as a string and then parse it but it is not good for unit testing and would like to update it.
Is it even possible with structure like this?
Ok, I solved this, maybe it can help someone.
I needed a class to represent the received object :
public class Filter
{
private string p { get; set; }
private string[] v { get; set; }
private string cp { get; set; }
private string[] cv { get; set; }
}
And in method definition I needed:
public SubjectStats BusinessSubjects(string country, string start, string end, [FromUri] Filter[] f)
The key was to define object as Filter[] in method signature.

WCF Data Service based on EF5 Model; how to add a custom type

I am trying to build a WCF Data Service with a ServiceMethod returning a custom type.
This type is used as a container to transmit multiple data collection at once. I am not able to define this type as entity or complex type.
public class BrfPackageDataContainer {
public ICollection<BrfFlight> Flights {
get;
set;
}
public ICollection<BrfFlight_Info> Flight_Infos {
get;
set;
}
public ICollection<BrfInfo> Infos {
get;
set;
}
public BrfPackageDataContainer() {
this.Flights = new List<BrfFlight>();
this.Flight_Infos = new List<BrfFlight_Info>();
this.Infos = new List<BrfInfo>();
}
}
This is my ServiceMethod declaration:
[WebGet]
[SingleResult]
public FlightInfoEntities.BrfPackageDataContainer GetBrfPackage () {
var brfPackageDataContainer = new FlightInfoEntities.BrfPackageDataContainer();
brfPackageDataContainer.Demodata();
return brfPackageDataContainer;
}
I got this running when using an empty dummy DataService as data source for the service class definition. But when I use my Entity Framework Model as data source the service refuse to start because of the missing metadata for the custom type.
My question is:
How can I use an EF Model as data source AND still use my custom type as a return value for my method.
Problem solved with a workaround:
I added 3 complex types to my modell, matching the data structure of each individual result set.
Furthermore I added a container class outside the data context which uses the complex types to hold the data in one object.
I extended the context class with a custom method to handle the stored procedure call and mapping the results to the appropriate complex types.ObjectContext.Translate helps a lot...
The WCF Data Service class is instantiated with a dummy DataContext. This enables metadata creation for my custom data container class which now can be used as return type of a custom WCF Data Service Method.
The data context is instantiated when the method is called.
Data container class` public class BrfPackageDataContainer {
public Guid TransactionId {
get;
set;
}
public List<BrfFlight> Flights {
get;
set;
}
public List<BrfFlight_Info> Flight_Infos {
get;
set;
}
public List<BrfInfo> Infos {
get;
set;
}
public BrfPackageDataContainer () {
this.Flights = new List<BrfFlight>();
this.Flight_Infos = new List<BrfFlight_Info>();
this.Infos = new List<BrfInfo>();
}
}`
context extension:
public partial class FlightInfoEntities
{
public virtual BrfPackageDataContainer GetBrfPackage(int? crewId, string operatorCode, string departure, int? flightId, DateTime? stdRangeStart,
DateTime? stdRangeEnd, string requestingApplication, string requestingComputerName,
string requestingACReg, ref Guid transactionId, int? specificInfoTypeId, byte? levelOfDetail,
bool? skipLog) {
using (DbCommand command = this.Database.Connection.CreateCommand()) {
command.CommandType = CommandType.StoredProcedure;
command.CommandText = "[dbo].[GetBrfPackage]";
...
var dataContainer = new BrfPackageDataContainer();
try {
this.Database.Connection.Open();
using (DbDataReader reader = command.ExecuteReader()) {
dataContainer.Flights = ((IObjectContextAdapter)this).ObjectContext.Translate<BrfFlight>(reader).ToList();
reader.NextResult();
dataContainer.Flight_Infos = ((IObjectContextAdapter)this).ObjectContext.Translate<BrfFlight_Info>(reader).ToList();
reader.NextResult();
dataContainer.Infos = ((IObjectContextAdapter)this).ObjectContext.Translate<BrfInfo>(reader).ToList();
}
return dataContainer;
} catch (Exception ex) {
throw ex;
}
}
WCF Data Service Method:
[WebGet]
[SingleResult]
public BrfPackageDataContainer GetBrfPackage () {
using (var brfCtx = new FlightInfoEntities()) {
Guid transactionId = new Guid();
var brfPackageDataContainer = brfCtx.GetBrfPackage(null,"4T",null,null,null,null,"test",Environment.MachineName,null,ref transactionId,null,3,false);
return brfPackageDataContainer;
}
}