使用mongoose查询来获取只有一个子文档

我有一个类似的数据结构:

var GrandGrandChild = mongoose.Schema({ attribute: String, id: Number }); var GrandChild = mongoose.Schema({ children: [GrandGrandChild], id: Number, irrelevantAttribute: String }); var Child = mongoose.Schema({ children: [GrandChild], id: Number, irrelevantAttribute2: String }); var Parent = mongoose.Schema({ children: [Child], id: Number, irrelevantAttribute3: String }); var GrandParent = mongoose.Schema({ children: [Parent], id: Number, irrelevantAttribute4: String }); 

这些是其中有很多子文档的集合。 请注意,ID对于其同胞来说是唯一的,但对具有相同模式的所有元素来说并不是唯一的。

所以一个祖父母可以有一个父母身份证0,而另一个祖父母也可以有一个父母身份证0,但一个祖父母不能有2父母身份证0。

唯一保存的模式是GrandParent模式,mongoose / mongodb使这个祖父母的所有数据成为一个很好的单个文件。 (正是我在找什么)

所以这里是我的问题:我有一个GrandParent ID,父ID,子ID,GrandChildID和GrandGrandChild ID,我想以某种方式只获取所有这些ID指向的GrandGrandChild对象。

丑陋的方式是,但目前唯一的方法,我可以开始工作,是做一个查询,得到这个大文件的爷爷,手动循环所有数组find正确的父母,然后循环再次find正确的孩子,然后再循环寻找合适的孙子,然后再循环,find在这里需要的孙子女。

我的问题是,我将如何撰写mongoose查询,只返回grandgrandchild文档,或祖父母文件只包含子属性,并在该属性只有父对象包括引用的子对象引用指的是孙子对象的孙子对象,允许以下结果:

 GRANDPARENT PARENT CHILD GRANDCHILD GRANDGRANDCHILD grandparent.children[0].children[0].children[0].children[0].attribute; 

我希望有人可以帮助我这个查询,到目前为止我是这样的:

 GrandParentModel.findOne( { "id" : 0, "children.id" : 0, "children.children.id" : 0, "children.children.children.id" : 0, "children.children.children.children.id" : 0 }, {"children.children.children.children.$" : 1}, callback); 

这个查询的问题是,unnessicary兄弟不剪掉。

我希望有人能帮助我。

Hylke Bron

       

网上收集的解决方案 "使用mongoose查询来获取只有一个子文档"

我问这个问题已经有一段时间了,但是我认为我发现了一种相当优雅的方式来处理这种结构。

在这种情况下,我将展示它如何与只有爷爷,父母和孩子。

我没有在每个文档(GrandParent.children,Parent.children)中存储子文档列表,而是创build了以下结构的唯一标识符:

 Child.referenceId = { grandparent: "some key to the grandparent of the parent", parent: "some key to the parent", child: "key of this child" }; Parent.referenceId = { grandparent: "some key to its grandparent", parent: "key of this parent" } GrandParent.referenceId = { grandparent: "key of this parent" } 

这将创build一个GrandParent> Parent> Child的层次结构。

模型将如下所示:

 var idStructure = { grandparent: { type: String, required: true }, parent: { type: String, required: false }, child: { type: String, required: false } }; var GrandParent = mongoose.Schema({ id: idStructure, irrelevantAttribute: String }); var Parent = mongoose.Schema({ id: idSructure, irrelevantAttribute: String }); var Child = mongoose.Schema({ id: idStructure, irrelevantAttribute: String }); 

请注意,父级不直接知道其父级,因为它们不作为子文档存储。 然而,通过referenceId,父母与孩子之间仍然存在联系。

当search一个GrandParent的整个家族树时,只需要执行3个查询,然后正确地连接它们:

 // First find all children which belong to the grandparent Child.find({"id.grandparent" : "some key to the grandparent"}) .exec(function(err, children) { if(err) return; Parent.find({"id.grandparent" : "some key to the grandparent"}) .exec(function(err, parents) { if(err) return; // Loop through the parents and children to connect them before returning to a client for(var i = 0; i < parents.length; i++) { var parent = parents[i]; parent.children = []; // loop through the children to check if they belong to the current parent for(var j = 0; j < children.length; j++) { var child = children[j]; if(parent.id.parent == child.id.parent) parent.children.push(child); } } // After filling the children into the parents, get the grandparents and do the same for the parents and grandparents as done for the children and parents. GrandParent.find({"id.grandparent" : "some key to the grandparent"}) .exec(function(err, grandparents) { // TODO: the same as done above (two loops, one loops the grandparents, other loops the parents // Once this is finished, we have a filled grandparent }); }); }); 

上面的代码将导致只有一个祖父母,充满了父母,这是充满了孩子。

没有更多的祖父母会被find的原因是因为祖父母的身份应该是唯一的,因为祖父母的身份certificate只有祖父母的财产。

我希望我的观点清楚,因为通过这种方法,人们可以很容易地search到一个特定的孩子,通过引用ID很容易得到它的父母,并且通过引用ID也可以得到它的父母。

这可能有点复杂,但是一旦你自己想出了方法,它就会变得非常简单。

Hylke

以一种干净的方式获得这种东西是非常困难的。

我没有find一个干净的解决scheme,但也许我可以帮你循环的事情。 你可以避免循环使用:var doc = parent.children.id(id); find一个子文件

我希望这可以帮助你。 问候,塞巴斯蒂安。

这对我工作

  model.find({_id:args.id},{ commentList: { $elemMatch: { _id: todo.commentList[todo.commentList.length-1] } } },(err, todos) => { if (err) reject(err) else resolve(todos) console.log(todos); }) 

$ elemMatch(投影)