我有以下结构 - 为简单起见我是缩写。几个属性。
您可以看到根文档(ProjectSchema)具有属性rootFolder
(FolderSchema),它可以具有 n嵌套级别。对于反序列化,我使用的是用C#编写的类 - ProjectSchema
和FolderSchema
,如上所述。
将BsonDocument反序列化到我的自定义类ProjectSchema
,我需要在Id 中找到特定的文件夹,并在该文件夹中插入新的FolderSchema
你能告诉我如何迭代,分别找到一个嵌套可能n级的特定文件,毕竟,如何在找到的元素中插入一个元素。
的结构
{
"_id" : ObjectId("5abce10cb02728006f1460fd"),
"owner_ref" : ObjectId("5ababb7188f6ba0079199dd0"),
"description" : "",
"rootFolder" : [
{
"_id" : ObjectId("5abce10cb02728006f1460fc"),
"folders" : [
{
"_id" : ObjectId("5abce9b5b02728006f1460ff"),
"folders" : [
{
"_id" : ObjectId("5abd5775b02728006f146130"),
"folders" : [
{
"_id" : ObjectId("5abd5781b02728006f146131"),
"folders" : [
{
"_id" : ObjectId("5abd578ab02728006f146132"),
"folders" : [],
"fileRefs" : [],
"docs" : [],
"name" : "NSubFolder1"
}
],
"fileRefs" : [],
"docs" : [],
"name" : "SubSubFolder1"
}
],
"fileRefs" : [],
"docs" : [],
"name" : "SubFolder1"
}
],
"fileRefs" : [],
"docs" : [],
"name" : "Folder1"
},
{
"_id" : ObjectId("5abd576db02728006f14612f"),
"folders" : [],
"fileRefs" : [],
"docs" : [],
"name" : "Folder2"
}
],
"fileRefs" : [],
"docs" : [
{
"_id" : ObjectId("5abce10cb02728006f1460fe"),
"name" : "main.tex"
}
],
"name" : "rootFolder"
}
]
}
项目架构 - 这包含文件夹和其他属性。这是我的主要文件。
public class ProjectSchema
{
[BsonId]
public BsonObjectId ProjectId { get; set; }
[BsonElement("description")]
public string Description { get; set; } = "some desc";
[BsonElement("owner_ref")]
public BsonObjectId OwnerRef { get; set; }
[BsonElement("rootFolder")]
public List<FolderSchema> RootFolder { get; set; } = new List<FolderSchema>();
public ProjectSchema()
{
ProjectId = new BsonObjectId(ObjectId.GenerateNewId());
}
}
文件夹架构,它包含文件夹
public class FolderSchema
{
[BsonId]
public BsonObjectId FolderId { get; set; }
[BsonElement("name")]
public string Name { get; set; } = "new folder";
[BsonElement("docs")]
public IEnumerable<DocSchema> Docs { get; set; } = new List<DocSchema>();
[BsonElement("fileRefs")]
public IEnumerable<FileSchema> FileRefs { get; set; } = new List<FileSchema>();
[BsonElement("folders")]
public IEnumerable<FolderSchema> Folders { get; set; } = new List<FolderSchema>();
public FolderSchema()
{
FolderId = new BsonObjectId(ObjectId.GenerateNewId());
}
}
不幸的是,这种方法没有成功,一切正常,但没有发生任何事情。我假设该过滤器中存在错误,因为Any()
仅针对第一级。我不知道如何定位FolderSchema嵌套的n级。
初始调用 - 在此示例中,我尝试在名为 HEUREKA 的文件夹 SubFolder1 中添加新文件夹
var projects = database.GetCollection<ProjectSchema>("projects");
var folder = new FolderSchema() { Name = "HEUREKA" };
var filter = Builders<ProjectSchema>.Filter.Where(p => p.ProjectId == new BsonObjectId(new ObjectId("5abce10cb02728006f1460fd"))
&& p.RootFolder.Any(l => l.FolderId == new BsonObjectId(new ObjectId("5abd5775b02728006f146130"))));
var update = Builders<ProjectSchema>.Update.Push(p => p.RootFolder, folder);
await projects.FindOneAndUpdateAsync(filter, update);
<小时/>
这是一个很好的观点,用最新的文件替换整个文件,最简单的 - 我可以承认,它的工作原理。然而,我的文件可能很大,所以我宁愿更新一块而不是整个文档。但是,如果我选择部分更新的选项,我仍然无法更新我的文档的某些部分,我不知道如何将它放在一起。所以我尝试了以下一个:
为了澄清,我知道ProjectId
ProjectSchema - 分别对于我要更新文件夹的项目,以及我知道父FolderId
FolderSchema < / em>我要添加一个新文件夹。
//**Schema simplification:**
Project Schema
Folder Schema
Folder Schema
Folder Schema
[n level folder schema]
Folder Schema
[n level]
写过滤器,接收名为“NSubFolder1”的父文件夹,或者我会使用文件夹ID而不是文件夹名称,因为我知道。
var eq = Builders<FolderSchema>.Filter.Eq(f => f.Name, "NSubFolder1");
var emN = Builders<FolderSchema>.Filter.ElemMatch(_ => _.Folders, eq);
写入过滤器以接收我想要添加文件夹的项目。
var eqProj = Builders<ProjectSchema>.Filter.Eq(p => p.ProjectId, "project id here");
var emP = Builders<ProjectSchema>.Filter.ElemMatch(_ => _.ProjectId, eqProj);
如何将这两个过滤器组合在一起,以便在ProjectSchema下接收指定的FolderSchema,然后将新的FolderSchema推送到父阵列?
答案 0 :(得分:2)
从概念上讲,您要做的是构建一个任意深度的递归$elemMatch
查询。我不认为使用您当前的数据库设计使用单个find / update命令可以完成此操作。
好像您事先知道了顶级ProjectId
的{{1}} - 如果是这种情况,则可以检索该文档,遍历它并构造一个n-等级深ProjectSchema
,将会这样描述(尽管写得不同)
FilterDefinition
虽然在这一点上,在反序列化对象中添加新的var eq = Builders<FolderSchema>.Filter.Eq(f => f.Name, "HEUREKA");
var emN = Builders<FolderSchema>.Filter.ElemMatch(_ => _.Folders, eq);
...
var em2 = Builders<FolderSchema>.Filter.ElemMatch(_ => _.RootFolder, em3);
var em1 = Builders<FolderSchema>.Filter.ElemMatch(_ => _.RootFolder, em2);
var emRoot = Builders<ProjectSchema>.Filter.ElemMatch(_ => _.RootFolder, em1);
并替换数据库中的文档似乎是最简单的。不过,如果您不想替换整个文档,您可以使用与生成ElemMatch查询相同的方式构建更新查询。
如果您能够更改模式,以便在集合中插入多个FolderSchema
对象而不是一个任意深度FolderSchema
文档,那么您似乎可以使用MongoDb Aggregate框架{{1如https://docs.mongodb.com/manual/reference/operator/aggregation/graphLookup/所述,https://docs.mongodb.com/manual/tutorial/model-tree-structures/
如果不了解您的情况,很难说这是一个更好的选择,还是仅仅是另一种选择。使用MongoDB Aggregate框架的能力绝对应该被认为是一个优势。