Я использую С# вместе с MongoDB. У меня есть класс, который может быть похож на это. Это образец, который что-то представляет, пожалуйста, не комментируйте дизайн класса.
[CollectionName("Venues")]
public class Venue
{
public string Name { get; set; }
public dictionary<string,object> Properties { get; set; }
}
var venue = new Venue
{
Name = "Venue 1",
Properties = new Dictionary<string,object>
{
{ "Chairs", "18" },
{ "Tables", "4" },
{ "HasWaterfall", true }
}
}
Предполагая, что у меня есть объект в коллекции, это выглядит так. Я хотел бы узнать из него можно сделать две вещи.
1: загрузить из базы данных только один элемент из словаря, в настоящее время я могу только видеть, как это можно сделать, загрузив весь запись из базы данных, а затем вручную получить значение по ключу.
2: Определить среднее значение одного элемента в базе данных. Например, по всем записям я хотел бы вычислить среднее стулья, опять же не загружая все записи, а затем делая это в памяти с помощью линк и тд....
В основном ваш образец документа сохраняется как JSON ниже:
{
"_id" : ObjectId("..."),
"Name" : "Venue 1",
"Properties" : {
"Chairs" : "18",
"Tables" : "4",
"HasWaterfall" : true
}
}
Это дает вам возможность определить проекцию, используя запись через точку:
var filter = Builders<Venue>.Filter.Eq(f => f.Name, "Venue 1");
var projection = Builders<Venue>.Projection.Include("Properties.Chairs");
List<BsonDocument> data = Col.Find(filter).Project(projection).ToList();
который возвращает нижеследующий BsonDocument:
{ "_id" : ObjectId("..."), "Properties" : { "Chairs" : "18" } }
Чтобы получить среднее значение, вам нужно использовать оператор $toInt, представленный в MongoDB 4.0, для преобразования ваших значений из строки в целое число. Пытаться:
var project = new BsonDocument()
{
{ "chairs", new BsonDocument() { { "$toInt", "$Properties.Chairs" } } }
};
var group = new BsonDocument()
{
{ "_id", "null" },
{ "avg", new BsonDocument() { { "$avg", "$chairs" } } }
};
var avg = Col.Aggregate().Project(project).Group(group).First();
вот альтернативный способ сделать это с помощью удобной библиотеки MongoDB.Entities.
using System.Collections.Generic;
using System.Linq;
using MongoDB.Entities;
namespace StackOverflow
{
class Program
{
[Name("Venues")]
public class Venue : Entity
{
public string Name { get; set; }
public Dictionary<string, object> Properties { get; set; }
}
static void Main(string[] args)
{
new DB("test");
var venue1 = new Venue
{
Name = "Venue 1",
Properties = new Dictionary<string, object> {
{ "Chairs", 28 },
{ "Tables", 4 },
{ "HasWaterfall", true }
}
};
venue1.Save();
var venue2 = new Venue
{
Name = "Venue 2",
Properties = new Dictionary<string, object> {
{ "Chairs", 38 },
{ "Tables", 4 },
{ "HasWaterfall", true }
}
};
venue2.Save();
var chairs = DB.Find<Venue, object>()
.Match(v => v.Name == "Venue 1")
.Project(v => new { ChairCount = v.Properties["Chairs"] })
.Execute();
var avgChairs = DB.Collection<Venue>()
.Average(v => (int)v.Properties["Chairs"]);
}
}
}
приводит к следующим запросам к базе данных:
получение стульев в зале 1:
db.runCommand({
"find": "Venues",
"filter": {
"Name": "Venue 1"
},
"projection": {
"Properties.Chairs": NumberInt("1"),
"_id": NumberInt("0")
},
"$db": "test"
})
получение среднего количества стульев по всем площадкам:
db.Venues.aggregate([
{
"$group": {
"_id": NumberInt("1"),
"__result": {
"$avg": "$Properties.Chairs"
}
}
}
])
Блестящий ответ и объяснение, спасибо. Я вижу, что он отлично работает в версии 4, я ограничен версией 3.6, Azure Cosmos DB, но я попытаюсь найти другую реализацию для $toInt, которой не существует. Еще действительно отличный ответ.