Looking through entire collection for string - c#

I'm making an authentication system for my C# program, I want the program to:
Connect to MongoDB server (done)
Go to right database & collection (done)
Look through all objects in collection and find if there's a key with a specific string value
Example of my objects in the collection:
_id: "XXX"
hwid: "the key/value pair that I want to filter for"
details: {
discord_id: int
discord_name: "string"
ip_address: "string"
serial: "XXX (same as _id name)"
}
So what I want to achieve is is that my program checks if my string (HardwareID.Output()) is in any of the collection's hwid keys.
The code I have so far:
public static void Connect()
{
var client = new MongoClient("connection works");
var database = client.GetDatabase("monza");
var collection = database.GetCollection<dynamic>("whitelist");
var filter = Builders<BsonDocument>.Filter.Eq("hwid", HardwareID.Output()); // grabs string from another class
var dataObjects = collection.Find(filter).ToList();
}
However I get the this error when trying this:
CS1503: Argument 2: cannot convert from 'MongoDB.Driver.FilterDefinition<MongoDB.Bson.BsonDocument>' to 'System.Linq.Expressions.Expression<System.Func<dynamic, bool>>'
Regardless of the error I don't think this is all I need to achieve my goal and I can't find any information on how to do this iN C#.

I do not know why you're using dynamic. Try this:
public static void Connect()
{
var client = new MongoClient("mongodb://127.0.0.1:27017");
var database = client.GetDatabase("monza");
var collection = database.GetCollection<BsonDocument>("whitelist");
var filter = Builders<BsonDocument>.Filter.Eq("hwid", HardwareID.Output()); // grabs string from another class
var dataObjects = collection.Find(filter).ToList();
}

Related

Retrieve "number" Luis entity in bot framework and display it right away

I am trying to recognize the entity "number" associated to the Intent command.
Here my entity in Luis
I use the Core Bot example and i let the classes names stay the same. https://github.com/microsoft/BotBuilder-Samples/tree/master/samples/csharp_dotnetcore/13.core-bot
I added the "number" entity here in flightbooking.cs
// Built-in entities
public DateTimeSpec[] datetime;
public double[] number;
I added this in flightbookingex.cs
public string Order_Number
=> Entities.number.ToString();
I created a class here : Order_Details.cs
namespace Microsoft.BotBuilderSamples
{
public class Order_Details
{
public string Order_Number { get; set; }
}
}
And when i want to retrieve the result in maindialog.cs
case FlightBooking.Intent.commande:
var commandemessagetext = "Voici le bon de commande";
var orderDetails = new Order_Details()
{
// Get destination and origin from the composite entities arrays.
Order_Number = luisResult.Order_Number,
};
var travelDateMsg = { result.Order_Number };
It says Cannot initialize an implicitly-typed variable with an array initializer and The name 'result' does not exist in the current context
I did not find another way to do this. I would like to display the result of travelDateMsg in the "case FlightBooking.Intent.commande". In the core bot example, it is displayed in another stepcontext.
i also tried the following piece of code, but it somehow does not work properly.
case FlightBooking.Intent.commande:
var commandemessagetext = "Here the order";
var order_count= luisResult.Entities;
var messageTexto = $"you have ordered {order_count}";
var message = MessageFactory.Text(messageTexto, messageTexto, InputHints.IgnoringInput);
await stepContext.Context.SendActivityAsync(message, cancellationToken);
the result is "you have ordered Microsoft.BotBuilderSamples.FlightBooking+_Entities"
Is there a simple way to return the value of an ententy in the same block of code than the one who detect the intent?
Thank you very much in advance for any suggestion on this
To answer the second error The name 'result' does not exist in the current context is because you have a typo:
case FlightBooking.Intent.commande:
var commandemessagetext = "Voici le bon de commande";
var orderDetails = new Order_Details()
{
// Get destination and origin from the composite entities arrays.
Order_Number = luisResult.Order_Number,
};
var travelDateMsg = { result.Order_Number };
There isn't a result there, there's a luisResult.

Couchbase Lite 2 + JsonConvert

The following code sample writes a simple object to a couchbase lite (version 2) database and reads all objects afterwards. This is what you can find in the official documentation here
This is quite a lot of manual typing since every property of every object must be transferred to the MutableObject.
class Program
{
static void Main(string[] args)
{
Couchbase.Lite.Support.NetDesktop.Activate();
const string DbName = "MyDb";
var db = new Database(DbName);
var item = new Item { Name = "test", Value = 5 };
// Serialization HERE
var doc = new MutableDocument();
doc.SetString("Name", item.Name);
doc.SetInt("Value", item.Value);
db.Save(doc);
using (var qry = QueryBuilder.Select(SelectResult.All())
.From(DataSource.Database(db)))
{
foreach (var result in qry.Execute())
{
var resultItem = new Item
{
// Deserialization HERE
Name = result[DbName].Dictionary.GetString("Name"),
Value = result[DbName].Dictionary.GetInt("Value")
};
Console.WriteLine(resultItem.Name);
}
}
Console.ReadKey();
}
class Item
{
public string Name { get; set; }
public int Value { get; set; }
}
}
From my research Couchbase lite uses JsonConvert internally, so there might be a way to simplify all that with the help of JsonConvert.
Anything like:
var json = JsonConvert.SerializeObject(item);
var doc = new MutableDocument(json); // No overload to provide raw JSON
or maybe
var data = JsonConvert.SerializeToDict(item); // JsonConvert does not provide this
var doc = new MutableDocument(data);
Is there or is this some kind of optimization and the preferred approach is by intend?
People ask about this quite often, but Couchbase Lite does not actually store JSON strings in the database. They are stored in a different format so this would not give the benefit that you think (the JSON would need to be reparsed and then broken down into the other format). I'd been pushing for a way to serialize classes directly instead of going through dictionary objects (which seems like the ultimate goal here) but our priority is on things that enterprise clients want and this doesn't seem to be one of them. Note that for it to make it in, it needs to be implemented in C# Java and Objective-C / Swift.
I don't know about JsonConvert but there seems to be a constructor that takes IDictionary<string, object> as argument. So I would try something like this (brain-compiled):
MutableDocument CreateDocument(object data)
{
if (data == null) return null;
var propertyValues = new Dictionary<string, object>();
foreach (var property in data.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
propertyValues[property.Name] = property.GetValue(data);
}
return new MutableDocument(propertyValues);
}
See if this works.

How to read a Mongo Document and save it to an object?

I need to read certain fields in documents from Mongo. I filtered out a document using the Filter.EQ() method but how can I find and store a field in that document? This is my code:
public void human_radioButton_Checked(object sender, RoutedEventArgs e)
{
Upload human = new Upload(); //opens connection to the database and collection
var filter = Builders<BsonDocument>.Filter.Eq("name", "Human");
race_desc description = new race_desc();
description.desc = Convert.ToString(filter);
desc_textBox.Text = description.desc;
However, this doesn't work since I didn't grab any fields, just the document. So how can I read a field called 'A' and store it into an object?
Thanks
When you define a filter using the Builders<BsonDocument>.Filter here, you merely define a filter that you can use/execute in a query. Much like storing a SQL string in a string variable.
What you missed here is executing the filter and actually retrieve the data. According to Mongodb C# driver doc:
var collection = _database.GetCollection<BsonDocument>("restaurants");
var filter = Builders<BsonDocument>.Filter.Eq("borough", "Manhattan");
var result = await collection.Find(filter).ToListAsync();
Then you can iterate the results and access the properties like
foreach(var result in results)
{
//do something here with result.your_property
}
And if you just want the first of the result
var result = (await collection.Find(filter).ToListAsync()).FirstOrDefault();
Now if you want to cast the BsonDocument you got now to your own class deserialize document using BsonSerializer:
var myObj = BsonSerializer.Deserialize<YourType>(result);
You can also map it to your own class:
var yourClass = new YourType();
yourClass.Stuff= result["Stuff"].ToString();

How to avoid adding a reference field in very small entries (thus avoiding doubling collection size)?

I have a User class that accumulates lots of DataTime entries in some List<DateTime> Entries field.
Occasionally, I need to get last 12 Entries (or less, if not reached to 12). It can get to very large numbers.
I can add new Entry object to dedicated collection, but then I have to add ObjectId User field to refer the related user.
It seems like a big overhead, for each entry that holds only a DateTime, to add another field of ObjectId. It may double the collection size.
As I occasionally need to quickly get only last 12 entries of 100,000 for instance, I cannot place these entries in a per-user collection like:
class PerUserEntries {
public ObjectId TheUser;
public List<DateTime> Entries;
}
Because it's not possible to fetch only N entries from an embedded array in a mongo query, AFAIK (if I'm wrong, it would be very gladdening!).
So am I doomed to double my collection size or is there a way around it?
Update, according to #profesor79's answer:
If your answer works, that will be perfect! but unfortunately it fails...
Since I needed to filter on the user entity as well, here is what I did:
With this data:
class EndUserRecordEx {
public ObjectId Id { get; set; }
public string UserName;
public List<EncounterData> Encounters
}
I am trying this:
var query = EuBatch.Find(u => u.UserName == endUser.UserName)
.Project<BsonDocument>(
Builders<EndUserRecordEx>.Projection.Slice(
u => u.Encounters, 0, 12));
var queryString = query.ToString();
var requests = await query.ToListAsync(); // MongoCommandException
This is the query I get in queryString:
find({ "UserName" : "qXyF2uxkcESCTk0zD93Sc+U5fdvUMPow" }, { "Encounters" : { "$slice" : [0, 15] } })
Here is the error (the MongoCommandException.Result):
{
{
"_t" : "OKMongoResponse",
"ok" : 0,
"code" : 9,
"errmsg" : "Syntax error, incorrect syntax near '17'.",
"$err" : "Syntax error, incorrect syntax near '17'."
}
}
Update: problem identified...
Recently, Microsoft announced their DocumentDB protocol support for MongoDB. Apparently, it doesn't support yet all projection operators. I tried it with mLab.com, and it works.
You can use PerUserEntries as this is a valuable document structure.
To get part of that array we need to add projection to query, so we can get only x elements and this is done server side.
Please see snippet below:
static void Main(string[] args)
{
// To directly connect to a single MongoDB server
// or use a connection string
var client = new MongoClient("mongodb://localhost:27017");
var database = client.GetDatabase("test");
var collection = database.GetCollection<PerUserEntries>("tar");
var newData = new PerUserEntries();
newData.Entries = new List<DateTime>();
for (var i = 0; i < 1000; i++)
{
newData.Entries.Add(DateTime.Now.AddSeconds(i));
}
collection.InsertOne(newData);
var list =
collection.Find(new BsonDocument())
.Project<BsonDocument>
(Builders<PerUserEntries>.Projection.Slice(x => x.Entries, 0, 3))
.ToList();
Console.ReadLine();
}
public class PerUserEntries
{
public List<DateTime> Entries;
public ObjectId TheUser;
public ObjectId Id { get; set; }
}

MongoDB: update only specific fields

I am trying to update a row in a (typed) MongoDB collection with the C# driver. When handling data of that particular collection of type MongoCollection<User>, I tend to avoid retrieving sensitive data from the collection (salt, password hash, etc.)
Now I am trying to update a User instance. However, I never actually retrieved sensitive data in the first place, so I guess this data would be default(byte[]) in the retrieved model instance (as far as I can tell) before I apply modifications and submit the new data to the collection.
Maybe I am overseeing something trivial in the MongoDB C# driver how I can use MongoCollection<T>.Save(T item) without updating specific properties such as User.PasswordHash or User.PasswordSalt? Should I retrieve the full record first, update "safe" properties there, and write it back? Or is there a fancy option to exclude certain fields from the update?
Thanks in advance
Save(someValue) is for the case where you want the resulting record to be or become the full object (someValue) you passed in.
You can use
var query = Query.EQ("_id","123");
var sortBy = SortBy.Null;
var update = Update.Inc("LoginCount",1).Set("LastLogin",DateTime.UtcNow); // some update, you can chain a series of update commands here
MongoCollection<User>.FindAndModify(query,sortby,update);
method.
Using FindAndModify you can specify exactly which fields in an existing record to change and leave the rest alone.
You can see an example here.
The only thing you need from the existing record would be its _id, the 2 secret fields need not be loaded or ever mapped back into your POCO object.
It´s possible to add more criterias in the Where-statement. Like this:
var db = ReferenceTreeDb.Database;
var packageCol = db.GetCollection<Package>("dotnetpackage");
var filter = Builders<Package>.Filter.Where(_ => _.packageName == packageItem.PackageName.ToLower() && _.isLatestVersion);
var update = Builders<Package>.Update.Set(_ => _.isLatestVersion, false);
var options = new FindOneAndUpdateOptions<Package>();
packageCol.FindOneAndUpdate(filter, update, options);
Had the same problem and since I wanted to have 1 generic method for all types and didn't want to create my own implementation using Reflection, I end up with the following generic solution (simplified to show all in one method):
Task<bool> Update(string Id, T item)
{
var serializerSettings = new JsonSerializerSettings()
{
NullValueHandling = NullValueHandling.Ignore,
DefaultValueHandling = DefaultValueHandling.Ignore
};
var bson = new BsonDocument() { { "$set", BsonDocument.Parse(JsonConvert.SerializeObject(item, serializerSettings)) } };
await database.GetCollection<T>(collectionName).UpdateOneAsync(Builders<T>.Filter.Eq("Id", Id), bson);
}
Notes:
Make sure all fields that must not update are set to default value.
If you need to set field to default value, you need to either use DefaultValueHandling.Include, or write custom method for that update
When performance matters, write custom update methods using Builders<T>.Update
P.S.: It's obviously should have been implemented by MongoDB .Net Driver, however I couldn't find it anywhere in the docs, maybe I just looked the wrong way.
Well there are many ways to updated value in mongodb.
Below is one of the simplest way I choose to update a field value in mongodb collection.
public string UpdateData()
{
string data = string.Empty;
string param= "{$set: { name:'Developerrr New' } }";
string filter= "{ 'name' : 'Developerrr '}";
try
{
//******get connections values from web.config file*****
var connectionString = ConfigurationManager.AppSettings["connectionString"];
var databseName = ConfigurationManager.AppSettings["database"];
var tableName = ConfigurationManager.AppSettings["table"];
//******Connect to mongodb**********
var client = new MongoClient(connectionString);
var dataBases = client.GetDatabase(databseName);
var dataCollection = dataBases.GetCollection<BsonDocument>(tableName);
//****** convert filter and updating value to BsonDocument*******
BsonDocument filterDoc = BsonDocument.Parse(filter);
BsonDocument document = BsonDocument.Parse(param);
//********Update value using UpdateOne method*****
dataCollection.UpdateOne(filterDoc, document);
data = "Success";
}
catch (Exception err)
{
data = "Failed - " + err;
}
return data;
}
Hoping this will help you :)

Categories