I have the below code and I am new to mongodb, I need help in finding an specific element in the collection.
using MongoDB.Bson;
using MongoDB.Driver;
namespace mongo_console {
public class User {
public ObjectId Id { get; set; }
public string name { get; set; }
public string pwd { get; set; }
}
class Program {
static void Main(string[] args)
{
MongoClient client = new MongoClient();
MongoServer server = client.GetServer();
MongoDatabase db = server.GetDatabase("Users");
MongoCollection<User> collection = db.GetCollection<User>("users");
User user = new User
{
Id = ObjectId.GenerateNewId(),
name = "admin",
pwd = "admin"
};
User user2 = new User
{
Id = ObjectId.GenerateNewId(),
name = "system",
pwd = "system"
};
collection.Save(user);
collection.Save(user2);
/*
* How do I collection.Find() for example using the name
*/
}
}
}
Once I find the user I will like to print it, is that posible or will find only return the position? if so, how do I print it?
I have seen some examples collection.Find(x => x.something) but I do not know what that x is or mean
To find a record you could use Lambda in find, for example:
var results = collection.Find(x => x.name == "system").ToList();
Alternatively you can use Builders which work with strongly typed Lambda or text:
var filter = Builders<User>.Filter.Eq(x => x.name, "system")
Or
var filter = Builders<User>.Filter.Eq("name", "system")
And then use find as above
// results will be a collection of your documents matching your filter criteria
// Sync syntax
var results = collection.Find(filter).ToList();
// Async syntax
var results = await collection.Find(filter).ToListAsync();
It also Varies according to the .Net framework version we are using. If we Use 2x driver it should look like :
var list = await collection.Find(new BsonDocument()).ToListAsync();
method 2
await collection.Find(new BsonDocument()).ForEachAsync(X=>Console.WriteLine(X));
Reference Example
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;
using MongoDB.Driver;
using MongoDB.Driver.Builders;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Mongo_console
{
class Program
{
public static void Main(string[] args)
{
MongoClient client = new MongoClient();
MongoServer server = client.GetServer();
MongoDatabase db = server.GetDatabase("admin");
MongoCollection<Book> collection = db.GetCollection<Book>("Book");
Book book1 = new Book
{
Id = ObjectId.GenerateNewId(),
name = "Reel To Real"
};
Book book2 = new Book
{
Id = ObjectId.GenerateNewId(),
name = "Life"
};
collection.Save(book1);
collection.Save(book2);
var query = Query<Book>.EQ(u => u.Id, new ObjectId("5a5ee6360222da8ad498f3ff"));
Book list = collection.FindOne(query);
Console.WriteLine( "Book Name " + list.name);
Console.ReadLine();
}
}
public class Book
{
[BsonId]
public ObjectId Id { get; set; }
public string name { get; set; }
public Book()
{
}
public Book(ObjectId id, string name)
{
this.Id = id;
this.name = name;
}
}
}
Related
Is there any chance to use graphLookup aggregate stage with POCO classes and not bson documents?
All examples I've found are using BsonDocuments and it makes me really confused.
Thanks.
let's take the example scenario of wanting to get back a breadcrumb result for a given category in a library...
here's a full program that inserts some seed data and uses a graphlookup aggregation stage to get the breadcrumb for the Mindfulness category:
note: i've used MongoDB.Entities library for brevity. the aggregate query would be the same for the official driver.
using MongoDB.Driver;
using MongoDB.Entities;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace TestApplication
{
public class Category : Entity
{
public string Name { get; set; }
public string ParentCategory { get; set; }
}
public class Result
{
public string[] BreadCrumb { get; set; }
}
public static class Program
{
private static async Task Main()
{
await DB.InitAsync("test");
await new[] {
new Category { Name = "Books" },
new Category { Name = "Sci-Fi", ParentCategory = "Books" },
new Category { Name = "Space", ParentCategory = "Sci-Fi" },
new Category { Name = "AI", ParentCategory = "Sci-Fi" },
new Category { Name = "Self-Help", ParentCategory = "Books" },
new Category { Name = "Mindfulness", ParentCategory = "Self-Help" },
new Category { Name = "Hypnotherapy", ParentCategory = "Self-Help" }
}.SaveAsync();
var collection = DB.Collection<Category>();
var result = await collection.Aggregate()
.Match(c => c.Name == "Mindfulness")
.GraphLookup<Category, string, string, string, Category, IEnumerable<Category>, object>(
from: collection,
connectFromField: nameof(Category.ParentCategory),
connectToField: nameof(Category.Name),
startWith: $"${nameof(Category.Name)}",
#as: "BreadCrumb",
depthField: "order")
.Unwind("BreadCrumb")
.SortByDescending(x => x["BreadCrumb.order"])
.Group("{_id:null, BreadCrumb:{$push:'$BreadCrumb'}}")
.Project("{_id:0, BreadCrumb:'$BreadCrumb.Name'}")
.As<Result>()
.ToListAsync();
var output = string.Join(" > ", result[0].BreadCrumb);
Console.WriteLine(output); //Books > Self-Help > Mindfulness
Console.ReadLine();
}
}
}
I am using CSharpScript.EvaluateAsync to generate a predicate from a string. Using string and int variables it works fine but if I try to pass in an enum variable in the string to convert it throws the error:
Message "(1,26): error CS0103: The name 'Status' does not exist in the current context" string
Here is the standalone reproduction:
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.CodeAnalysis.CSharp.Scripting;
using Microsoft.CodeAnalysis.Scripting;
namespace PredicateParser
{
class Program
{
static void Main(string[] args)
{
var albums = new List<Album>
{
new Album { Quantity = 10, Artist = "Betontod", Title = "Revolution", Status = Status.Offline},
new Album { Quantity = 50, Artist = "The Dangerous Summer", Title = "The Dangerous Summer", Status = Status.Offline },
new Album { Quantity = 200, Artist = "Depeche Mode", Title = "Spirit", Status = Status.Online },
};
var albumFilter1 = "album => album.Quantity > 20 && album.Quantity < 200"; //works fine
var albumFilter2 = "album => album.Status == Status.Online"; //Throws exception
var predicate1 = CreatePredicate<Album>(albumFilter1);
var predicate2 = CreatePredicate<Album>(albumFilter2);
var filteredAlbums1 = albums.Where(predicate1).ToList();
var filteredAlbums2 = albums.Where(predicate2).ToList();
}
public static Func<T, bool> CreatePredicate<T>(string command)
{
var options = ScriptOptions.Default.AddReferences(typeof(T).Assembly);
Func<T, bool> predicate = CSharpScript.EvaluateAsync<Func<T, bool>>(command, options).Result;
return predicate;
}
}
public class Album
{
public int Quantity { get; set; }
public string Title { get; set; }
public string Artist { get; set; }
public Status Status { get; set; }
}
public enum Status
{
Online,
Offline
}
}
How can I get it to work with enums?
var options = ScriptOptions.Default.AddReferences(typeof(T).Assembly).AddImports(nameof(PredicateParser));
You forgot to add "using namespace" :)
In this case, there's no error if you fully qualify it with the namespace.
"album => album.Status == PredicateParser.Status.Online"
I am attempting to use System.Linq.Dynamic.Core (https://github.com/StefH/System.Linq.Dynamic.Core) in order to create dynamic queries.
Following the example given on the github page, I have tried the following
lstContacts = lstContacts.Where("#0 == true", "active");
However I get the following result:
'active is not a valid value for Boolean
Reference this library:
using System.Linq.Dynamic;
And make your query like that:
string columnName = "active";
var lstContacts = lstContacts.Where(columnName + " == true");
Here is a working example:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic;
public class Program
{
public static void Main()
{
var lstContacts = new List<Contact>{
new Contact{Id = 1, Active = true, Name = "Chris"},
new Contact{Id = 2, Active = true, Name = "Scott"},
new Contact{Id = 3, Active = true, Name = "Mark"},
new Contact{Id = 4, Active = false, Name = "Alan"}};
string columnName = "Active";
List<Contact> results = lstContacts.Where(String.Format("{0} == true", columnName)).ToList();
foreach (var item in results)
{
Console.WriteLine(item.Id.ToString() + " - " + item.Name.ToString());
}
}
}
public class Contact
{
public int Id
{
get;
set;
}
public bool Active
{
get;
set;
}
public string Name
{
get;
set;
}
}
You can experiment with this .net-fiddle-here
I've just started learning Linq, and I'm trying to map a database table to a class, but I can't get it to work with a private constructor.
My code:
namespace LinqTest
{
using System.Collections.Generic;
using System.Data.Linq;
using System.Data.Linq.Mapping;
using System.Linq;
[Table(Name = "tblCity")]
public class City
{
private City()
{
}
[Column(IsPrimaryKey = true, Name = "CityId")]
public int Id { get; private set; }
[Column(Name = "CityName")]
public string Name { get; private set; }
public static List<City> GetList()
{
var dataContext = new DataContext(Database.ConnectionString());
var cities = dataContext.GetTable<City>();
var iQueryable =
from city in cities
select city;
return iQueryable.ToList();
}
}
}
I've also tried mapping to a new instance:
var list = new List<City>();
foreach (var iCity in iQueryable)
{
var city = new City
{
Id = iCity.Id,
Name = iCity.Name
};
list.Add(city);
}
return list;
What can I do to make this work? I'm open to alternative methods.
Thanks
You cant use iqueryable object in foreach. Because this is just a query. You must get objects with ToList(). Pls try this:
var list = new List<City>();
foreach (var iCity in iQueryable.ToList())// return iqueryable to list
{
var city = new City
{
Id = iCity.Id,
Name = iCity.Name
};
list.Add(city);
}
return list;
Or You can search automapper. One example here
Ill keep the question short, as i suspect the answer may be a short no..
I would like to be able to pass a query into an entity framework function, to enable dynamic runtime querying through the ui to the database?
I imagined this to be like passing an IQueryable into a method, but exactly how i would go about this, i am a little unsure at the moment. Am i thinking about this the wrong way? Perhaps querying in the business layer, not semi-directly to the database?
Based on the comments, I'm providing the two options.
Based on a set of options given to the user.
Use a TreeExpression to build you expression dynamically, somthing like the example above (this example is indeed too simple, but you can have an idea).
ParameterExpression numParam = Expression.Parameter(typeof(int), "num");
ConstantExpression five = Expression.Constant(5, typeof(int));
BinaryExpression numLessThanFive = Expression.LessThan(numParam, five);
Expression<Func<int, bool>> lambda1 = Expression.Lambda<Func<int, bool>>(numLessThanFive, new ParameterExpression[] { numParam });
This link will give you some more info on the subject: https://msdn.microsoft.com/en-us/library/bb882637.aspx
For letting the user type some expression and converting it to a query, search for Antlr http://www.antlr.org/, or some tool like this, padronize the expression syntax you want to implement and go for the 1ยบ solution to build the expression.
My example code is below. You'll need to install the following packages...
install-package entityframework
install-package newtonsoft.json
Be aware that this code is susceptible to injection by inserting valid VB.NET code to escape the query.
I compiled the code into 30742268.exe, which you can see is added as a reference for the IContext interface, etc.
using System;
using System.Linq;
using System.Text;
using Microsoft.VisualBasic;
using System.CodeDom.Compiler;
using Model;
using System.Collections.Generic;
using System.Data.Entity;
using Newtonsoft.Json;
namespace _30742268 {
class Program {
const String queryWrapperCode = #"
Imports System.Linq
Imports System.Data.Entity
Imports Model
Public Class DynamicQuery
Implements IDynamicQuery
Public Function Run(data As IContext) As IQueryable Implements IDynamicQuery.Run
Return {0}
End Function
End Class
";
static void Main(String[] args) {
using (var provider = new VBCodeProvider()) {
var parameters = new CompilerParameters();
parameters.ReferencedAssemblies.Add("System.Core.dll");
parameters.ReferencedAssemblies.Add("EntityFramework.dll");
parameters.ReferencedAssemblies.Add("30742268.exe");
parameters.GenerateInMemory = true;
Console.WriteLine("Enter LINQ queries, 'demo' for an example, 'exit' to stop:");
for (;;) {
try {
var dynamicQueryString = Console.ReadLine();
if (dynamicQueryString == "exit")
return;
if (dynamicQueryString == "demo")
Console.WriteLine(dynamicQueryString = "from person in data.People where person.Name.Length = 4");
var results = provider.CompileAssemblyFromSource(parameters, String.Format(queryWrapperCode, dynamicQueryString));
if (results.Errors.HasErrors) {
var sb = new StringBuilder();
foreach (CompilerError error in results.Errors) {
sb.AppendLine(String.Format("Error ({0}): {1}", error.ErrorNumber, error.ErrorText));
}
throw new InvalidOperationException(sb.ToString());
}
var assembly = results.CompiledAssembly;
var assemblyType = assembly.GetTypes().Single(x => typeof (IDynamicQuery).IsAssignableFrom(x));
var constructorInfo = assemblyType.GetConstructor(new Type[] {});
var dynamicQuery = (IDynamicQuery) constructorInfo.Invoke(null);
using (var context = new Context()) {
dynamic result = dynamicQuery.Run(context);
foreach (var person in result)
Console.WriteLine(person);
}
}
catch (Exception exception) {
Console.WriteLine(exception);
}
}
}
}
}
}
namespace Model {
public interface IDynamicQuery {
IQueryable Run(IContext context);
}
public abstract class Entity {
public override String ToString() {
return JsonConvert.SerializeObject(this, Formatting.Indented, new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore });
}
}
public class Person : Entity {
public Int64 Id { get; protected set; }
public String Name { get; set; }
public virtual Home Home { get; set; }
}
public class Home : Entity {
public Int64 Id { get; protected set; }
public String Address { get; set; }
public virtual ICollection<Person> Inhabitants { get; set; }
}
public interface IContext {
IQueryable<Person> People { get; set; }
IQueryable<Home> Homes { get; set; }
}
public class Context : DbContext, IContext {
public virtual DbSet<Person> People { get; set; }
public virtual DbSet<Home> Homes { get; set; }
IQueryable<Person> IContext.People {
get { return People; }
set { People = (DbSet<Person>)value; }
}
IQueryable<Home> IContext.Homes {
get { return Homes; }
set { Homes = (DbSet<Home>)value; }
}
public Context() {
Configuration.ProxyCreationEnabled = false;
Database.SetInitializer(new ContextInitializer());
}
}
class ContextInitializer : DropCreateDatabaseAlways<Context> {
protected override void Seed(Context context) {
var fakeSt = new Home {Address = "123 Fake St."};
var alabamaRd = new Home {Address = "1337 Alabama Rd."};
var hitchhikersLn = new Home {Address = "42 Hitchhiker's Ln."};
foreach (var home in new[] {fakeSt, alabamaRd, hitchhikersLn})
context.Homes.Add(home);
context.People.Add(new Person { Home = fakeSt , Name = "Nick" });
context.People.Add(new Person { Home = fakeSt , Name = "Paul" });
context.People.Add(new Person { Home = fakeSt , Name = "John" });
context.People.Add(new Person { Home = fakeSt , Name = "Henry" });
context.People.Add(new Person { Home = alabamaRd , Name = "Douglas" });
context.People.Add(new Person { Home = alabamaRd , Name = "Peter" });
context.People.Add(new Person { Home = alabamaRd , Name = "Joshua" });
context.People.Add(new Person { Home = hitchhikersLn, Name = "Anne" });
context.People.Add(new Person { Home = hitchhikersLn, Name = "Boris" });
context.People.Add(new Person { Home = hitchhikersLn, Name = "Nicholes" });
context.People.Add(new Person { Home = hitchhikersLn, Name = "Betty" });
context.SaveChanges();
}
}
}