【问题标题】:How to create index based on nested array element in C# Mongodb strongly typed driver如何在 C# Mongodb 强类型驱动程序中基于嵌套数组元素创建索引
【发布时间】:2019-03-14 18:51:14
【问题描述】:

这个问题的原理与this one 完全相同,但是当对象嵌套在集合的数组中时,我想在对象属性上使用强类型方法创建索引。

我可以使用:

new CreateIndexModel<T>( Builders<T>.IndexKeys.Ascending( a ) )

其中 a 是访​​问直接属性的表达式。

但我没有找到类似的东西:

Builders<Library>.Filter.ElemMatch(x => x.Author.Books, b => b.IsVerified == false));

这样我就可以将嵌套在数组中的对象的某些字段定义为索引,该数组是集合的成员。

这可能吗?如何做到?

【问题讨论】:

    标签: c# mongodb mongodb-.net-driver


    【解决方案1】:

    考虑以下数据模型:

    public class Course
    {
       public string Name { get; set; }
       public string Teacher { get; set; }
    }
    
    public class Student
    {
      public string Name { get; set; }
      public int Age { get; set; }
      public ReadOnlyCollection<Course> Courses { get; set; }
    }
    

    您可以通过以下方式在字段 Courses 上创建升序多键索引:

    using MongoDB.Driver;
    using System;
    using System.Collections.Generic;
    using System.Threading.Tasks;
    
    namespace ConsoleApp1
    {
      public static class Program
      {
        private static MongoClient Client;
        private static IMongoDatabase Database;
        private static IMongoCollection<Student> Collection;
    
        public static async Task Main(string[] args)
        {
          Client = new MongoClient();
          Database = Client.GetDatabase("test-index");
          Collection = Database.GetCollection<Student>("students");
    
          var courses1 = new List<Course>()
          {
            new Course { Name = "Math", Teacher = "Bob" }
          }.AsReadOnly();
    
          var courses2 = new List<Course>()
          {
            new Course { Name = "Computer Science", Teacher = "Alice" }
          }.AsReadOnly();
    
          var mark = new Student
          {
            Name = "Mark",
            Courses = courses1,
            Age = 20
          };
    
          var lucas = new Student
          {
            Name = "Lucas",
            Courses = courses2,
            Age = 22
          };
    
          await Collection.InsertManyAsync(new[] { mark, lucas }).ConfigureAwait(false);
    
    
          var model = new CreateIndexModel<Student>(
            Builders<Student>.IndexKeys.Ascending(s => s.Courses));
    
          await Collection.Indexes.CreateOneAsync(model).ConfigureAwait(false);
    
          Console.WriteLine("All done !");
        }
      }
    }
    

    此查询由您创建的索引提供服务: db.students.find({Courses: {"Name": "Math", "Teacher": "Bob"}})

    如果您不想在整个数组 Courses 上创建索引,而是希望在嵌套对象(Course 对象)的字段名称上创建索引,那么可以这样做:

    using MongoDB.Driver;
    using System;
    using System.Collections.Generic;
    using System.Threading.Tasks;
    
    namespace ConsoleApp1
    {
      public static class Program
      {
        private static MongoClient Client;
        private static IMongoDatabase Database;
        private static IMongoCollection<Student> Collection;
    
        public static async Task Main(string[] args)
        {
          Client = new MongoClient();
          Database = Client.GetDatabase("test-index");
          Collection = Database.GetCollection<Student>("students");
    
          var courses1 = new List<Course>()
          {
            new Course { Name = "Math", Teacher = "Bob" }
          }.AsReadOnly();
    
          var courses2 = new List<Course>()
          {
            new Course { Name = "Computer Science", Teacher = "Alice" }
          }.AsReadOnly();
    
          var mark = new Student
          {
            Name = "Mark",
            Courses = courses1,
            Age = 20
          };
    
          var lucas = new Student
          {
            Name = "Lucas",
            Courses = courses2,
            Age = 22
          };
    
          await Collection.InsertManyAsync(new[] { mark, lucas }).ConfigureAwait(false);
    
    
          var model = new CreateIndexModel<Student>(
            Builders<Student>.IndexKeys.Ascending("Courses.Name"));
    
          await Collection.Indexes.CreateOneAsync(model).ConfigureAwait(false);
    
          Console.WriteLine("All done !");
        }
      }
    }
    

    此查询由您创建的索引提供服务:db.students.explain("executionStats").find({"Courses.Name": "Math"})

    在我的第二个示例中避免使用魔术字符串的一种可能方法是利用 C# 运算符的 nameof 的强大功能: $"{nameof(Student.Courses)}.{nameof(Course.Name)}"

    【讨论】:

    • 感谢您的详细回答。但它倾向于确认我们必须使用字符串(“Courses.Name”)而不是基于强类型表达式的定义来定义索引,不是吗?
    • 嗨 @lemon 我认为 Mongodb 的 jira 上的 this issue 确认,目前不支持类型安全。
    • @lemon 请参阅我上面的评论,了解缓解问题的可能方法
    • 好的,非常感谢,您提到的问题没有解决时,我会使用您的字符串方法。
    【解决方案2】:

    这是使用MongoDB.Entities 便利库为嵌套字段创建索引的强类型方法。 [免责声明:我是作者]

    using MongoDB.Entities;
    using System.Collections.Generic;
    
    namespace StackOverflow
    {
        public class Program
        {
            public class Parent : Entity
            {
                public Child[] Children { get; set; }
            }
    
            public class Child
            {
                public List<Friend> Friends { get; set; }
            }
    
            public class Friend
            {
                public string Name { get; set; }
            }
    
            static void Main(string[] args)
            {
                new DB("test");
    
                DB.Index<Parent>()
                  .Key(p => p.Children[-1].Friends[-1].Name, KeyType.Ascending)
                  .Create();
    
            }
        }
    }
    

    上面使用以下命令在嵌套两层的名称字段上创建升序索引:

    db.Parent.createIndex({
        "Children.Friends.Name": NumberInt("1")
    }, {
        name: "Children.Friends.Name(Asc)",
        background: true
    })
    

    【讨论】:

      猜你喜欢
      • 2017-08-08
      • 2018-11-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-17
      • 2022-11-28
      • 2020-02-20
      • 1970-01-01
      相关资源
      最近更新 更多