Получение общей информации о коллекциях MongoDB с FSharp

Можно ли получить основную информацию обо всех коллекциях в MongoDB с помощью F#?

У меня есть MongoDB с> 450 коллекциями. Я могу получить доступ к db с помощью

open MongoDB.Bson
open MongoDB.Driver
open MongoDB.Driver.Core 
open MongoDB.FSharp
open System.Collections.Generic

let connectionString = "mystring"
let client = new MongoClient(connectionString)
let db = client.GetDatabase(name = "Production")

Я подумал о том, чтобы попытаться просто собрать все коллекции, затем прокрутить каждое имя коллекции и получить основную информацию о каждой коллекции с помощью

let collections = db.ListCollections()

а также

db.GetCollection([name of a collection])

но db.GetCollection([name]) требует, чтобы я определял тип, чтобы извлекать информацию о каждой коллекции. Это сложно для меня, так как я не хочу определять тип для каждой коллекции, из которых есть> 450, и, честно говоря, я действительно мало знаю об этой БД. (На самом деле, никто в моей организации не делает, поэтому я пытаюсь собрать очень простой словарь данных.)

Является ли определение типа для каждой коллекции действительно необходимым? Могу ли я использовать методы MongoCollection, доступные здесь, без необходимости определять тип для каждой коллекции?


EDIT: В конечном счете, я хотел бы иметь возможность выводить имя коллекции, n документов в каждой коллекции, список имен полей в каждой коллекции и список каждого типа поля.

Ответы

Ответ 1

Я решил написать свои примеры на С#, поскольку я больше знаком с драйвером С#, и это тег, указанный в вопросе. Вы можете запустить агрегацию против каждой коллекции, чтобы найти все поля верхнего уровня и их типы (mongodb) для каждого документа.

Агрегация выполняется в 3 этапа. Предположим, что входные данные - это 10 документов, все из которых имеют следующую форму:

{
  "_id": ObjectId("myId"),
  "num": 1,
  "str": "Hello, world!"
}
  1. $project Преобразование каждого документа в массив документов со значениями fieldName и fieldType. Выводит 10 документов с одним полем массива. Поле массива будет иметь 3 элемента.

  2. $unwind массивы полевой информации. Выводит 30 документов каждый с одним полем, соответствующим элементу, из выхода шага 1.

  3. $group поля по fieldName и fieldType для получения отдельных значений. Выводит 3 документа. Поскольку в этом примере все поля с одинаковым именем имеют одинаковый тип, для каждого поля есть только один конечный выходной документ. Если два разных документа определили одно и то же поле, одно в виде строки и одно как int, в этом результирующем наборе для обоих будут отдельные записи.


// Define our aggregation steps.
// Step 1, $project:
var project = new BsonDocument
{ {
    "$project", new BsonDocument
    {
        {
            "_id", 0
        },
        {
            "fields", new BsonDocument
            { {
                "$map", new BsonDocument
                {
                    { "input", new BsonDocument { { "$objectToArray", "$$ROOT" } } },
                    { "in", new BsonDocument {
                        { "fieldName", "$$this.k" },
                        { "fieldType", new BsonDocument { { "$type", "$$this.v" } } }
                    } }
                }
            } }
        }
    }
} };

// Step 2, $unwind
var unwind = new BsonDocument
{ {
    "$unwind", "$fields"
} };

// Step 3, $group
var group = new BsonDocument
{
    {
        "$group", new BsonDocument
        {
            {
                "_id", new BsonDocument
                {
                    { "fieldName", "$fields.fieldName" },
                    { "fieldType", "$fields.fieldType" }
                }
            }
        }
    }
};

// Connect to our database
var client = new MongoClient("myConnectionString");
var db = client.GetDatabase("myDatabase");

var collections = db.ListCollections().ToEnumerable();

/*
We will store the results in a dictionary of collections.
Since the same field can have multiple types associated with it the inner value corresponding to each field is 'List<string>'.

The outer dictionary keys are collection names. The inner dictionary keys are field names.
The inner dictionary values are the types for the provided inner dictionary key (field name).
List<string> fieldTypes = allCollectionFieldTypes[collectionName][fieldName]
*/
Dictionary<string, Dictionary<string, List<string>>> allCollectionFieldTypes = new Dictionary<string, Dictionary<string, List<string>>>();

foreach (var collInfo in collections)
{
    var collName = collInfo["name"].AsString;
    var coll = db.GetCollection<BsonDocument>(collName);

    Console.WriteLine("Finding field information for " + collName);                

    var pipeline = PipelineDefinition<BsonDocument, BsonDocument>.Create(project, unwind, group);
    var cursor = coll.Aggregate(pipeline);
    var lst = cursor.ToList();

    allCollectionFieldTypes.Add(collName, new Dictionary<string, List<string>>());
    foreach (var item in lst)
    {
        var innerDict = allCollectionFieldTypes[collName];

        var fieldName = item["_id"]["fieldName"].AsString;
        var fieldType = item["_id"]["fieldType"].AsString;

        if (!innerDict.ContainsKey(fieldName))
        {
            innerDict.Add(fieldName, new List<string>());
        }

        innerDict[fieldName].Add(fieldType);
    }
}

Теперь вы можете выполнять итерацию по вашему набору результатов:

foreach(var collKvp in allCollectionFieldTypes)
{
  foreach(var fieldKvp in collKvp.Value)
  {
    foreach(var fieldType in fieldKvp.Value)
    {
      Console.WriteLine($"Collection {collKvp.Key} has field name {fieldKvp.Key} with type {fieldType}");
    }
  }
}