简体   繁体   English

mongodb子文档的投影并在C#中将子文档作为类获取

[英]Projection of mongodb subdocument and get subdocument as class in c#

Hi. 你好。 I have a Collection named "Level" with this class structure : 我有一个名为“ Level”的具有此类结构的集合:

    public class Level 
    {
      [BsonId]
      public string Id {get; set;}
      public string Name { get; set; }
      public int Number { get; set; }
      public int TotalScore { get; set; }
      public int QuestionCount { get; set; }
      public IEnumerable<ConnectingQuestion> ConnectingQuestions { get; set; }
    }
    public class ConnectingQuestion 
    {
      [BsonId]
      public string Id { get; set; }
      public int QuestionNumber { get; set; }        
      public string Description { get; set; }       
      public string Type { get; set; }  
      public string Title { get; set; }
    }

and collection structure like this : 和这样的收集结构:

{ 
"_id" : "64e850f95322e01e88f131a2", 
"Name" : "First Level", 
"Number" : NumberInt(1), 
"TotalScore" : NumberInt(2690), 
"QuestionCount" : NumberInt(40), 
"ConnectingQuestions" : [
    {
        "_id" : "5a130570738634297478fb43", 
        "QuestionNumber" : NumberInt(1), 
        "Description" : "desc", 
        "Type" : "sc", 
        "Title" : "title1", 
     },
     {
        "_id" : "5a130570738634297478fb76", 
        "QuestionNumber" : NumberInt(2), 
        "Description" : "desc", 
        "Type" : "sc", 
        "Title" : "title2", 
     },
     {
        "_id" : "5a130570738634297478fb23", 
        "QuestionNumber" : NumberInt(3), 
        "Description" : "desc", 
        "Type" : "sc", 
        "Title" : "title3", 
     }
    ]
}
{ 
"_id" : "59e850f95322e01e88f131c1", 
"Name" : "Second Level", 
"Number" : NumberInt(2), 
"TotalScore" : NumberInt(8000), 
"QuestionCount" : NumberInt(20), 
"ConnectingQuestions" : [
    {
        "_id" : "5a130570738634297478fa56", 
        "QuestionNumber" : NumberInt(1), 
        "Description" : "desc", 
        "Type" : "sc", 
        "Title" : "title1", 
     },
     {
        "_id" : "5a130570738634297478fb66", 
        "QuestionNumber" : NumberInt(2), 
        "Description" : "desc", 
        "Type" : "sc", 
        "Title" : "title2", 
     },
     {
        "_id" : "5a130570738634297478fe32", 
        "QuestionNumber" : NumberInt(3), 
        "Description" : "desc", 
        "Type" : "sc", 
        "Title" : "title3", 
     }
    ]
}

i need to write Query in c# that first select level with specified id and in selected level, select and return "ConnectingQuestion" subcollection with certain "QuestionNumber" in type of ConnectingQuestion class and not BsonDocument. 我需要在C#中编写Query,该查询首先选择具有指定ID的级别并在所选级别中,选择并返回具有“连接问题”类而不是BsonDocument类型的某些“问题编号”的“连接问题”子集合。 A pseudo-query like this: 这样的伪查询:

 ConnectingQuestion cq = MongoDB.Levels.find(level.id == "59e850f95322e01e88f131c1" && level.ConnectingQuestions.QuestionNumber == 2).Projection(level.ConnectingQuestions).SingleOrDefault();

Here are two possible solutions - there may be simpler ones... 这是两种可能的解决方案-可能有更简单的解决方案...

Version 1: Using find() and project() only plus some BSON magic 版本1:仅使用find()project()以及一些BSON魔术

var collection = new MongoClient().GetDatabase("test").GetCollection<Level>("test");

var projection = Builders<Level>.Projection.ElemMatch(level => level.ConnectingQuestions, q => q.QuestionNumber == 2);
var bsonDocument = collection
    // filter out anything that we're not interested in
    .Find(level => level.Id == "59e850f95322e01e88f131c1")
    .Project(projection)
    .First();
// get first (single!) item from "ConnectingQuestions" array
bsonDocument = bsonDocument.GetElement("ConnectingQuestions").Value.AsBsonArray[0].AsBsonDocument;
// deserialize bsonDocument into ConnectingQuestions instance
ConnectingQuestion cq = BsonSerializer.Deserialize<ConnectingQuestion>(bsonDocument);

Version 2: Using the aggregation framework ( $filter needs MongoDB >= v3.2) 版本2:使用聚合框架( $filter需要MongoDB> = v3.2)

var collection = new MongoClient().GetDatabase("test").GetCollection<Level>("test");

var cq = collection.Aggregate()
    // filter out anything that we're not interested in
    .Match(level => level.Id == "59e850f95322e01e88f131c1")
    // filter the ConnectingQuestions array to only include the element with QuestionNumber == 2
    .Project<Level>("{ 'ConnectingQuestions': { $filter: { input: '$ConnectingQuestions', cond: { $eq: [ '$$this.QuestionNumber', 2 ] } } } }")
    // move the first (single!) item from "ConnectingQuestions" array to the document root level
    .ReplaceRoot(q => q.ConnectingQuestions.ElementAt(0))
    .FirstOrDefault();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM