Как создать индекс на основе вложенного элемента массива в строгом типе драйвера C # Mongodb - PullRequest
2 голосов
/ 14 марта 2019

Этот вопрос по тем же принципам, что и , этот , но я бы хотел создать индекс с использованием строго типизированного подхода к свойству объекта, когда этот объект вложен в массив коллекции.

Я могу использовать:

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

где a - это выражение, которое обращается к прямому свойству.

Но я не нашел ничего похожего на:

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

чтобы я мог определить в качестве индекса какое-то поле объекта, вложенного в массив, который является членом коллекции.

Возможно ли это сделать и как?

Ответы [ 2 ]

1 голос
/ 14 марта 2019

Рассмотрим следующую модель данных:

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; }
}

Вы можете создать восходящий индекс многопользовательского ключа в поле Курсы следующим образом:

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, но вместо этого вам нужен индекс для поля Name вложенного объекта (объекта 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"})

Возможный способ избежать использования магических строк в моем втором примере - использовать силу оператора nameof C #: $"{nameof(Student.Courses)}.{nameof(Course.Name)}"

0 голосов
/ 12 июня 2019

это строго типизированный способ создания индексов для вложенных полей с использованием вспомогательной библиотеки 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
})
...