2013-04-23 70 views
7

我有一个类似的数据结构,因为这:用猫鼬查询得到的只有一个子文档

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对于它们的兄弟姐妹是唯一的,但对于具有相同模式的所有元素不是唯一的。

所以一个盛大的父母可以有ID为0的父母和祖父母的另一个也可以有父ID为0,但一个祖父母不能有2位家长ID为0

是被保存的唯一模式是GrandParent架构,并且mongoose/mongodb为这个祖父母的所有数据创建了一个很好的大单文档。 (正是我在找什么)

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

丑陋的方式是,但目前我可以开始工作的唯一方法是做一个查询,获取这个GrandParent的大文档,并手动循环遍历所有数组以找到正确的Parent,然后再次循环找到合适的孩子,然后再循环寻找合适的孙子,然后再次循环,找到需要在这里工作的孙子女。

我的问题是,我将如何编写一个查询猫鼬,要么只返回grandgrandchild文档,或只包含子属性的祖父文件,并在该属性只有父对象包括引用子这指的是指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勒布朗

回答

3

我问了这个问题已经有一段时间了,但我想我找到了一种相当优雅的方式来处理这些结构。

在这种情况下,我将展示它如何与只有GrandParent,父母和孩子一起工作。

而不是存储每个文档中的子文档列表(GrandParent.children,Parent。儿童),我创建了以下结构的唯一标识符:

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" 
} 

这会创建一个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,Parent和Child之间仍然存在关联。

当祖父母的整个谱系图搜索,一个只会执行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 
     }); 

    }); 
}); 

上面的代码将导致在短短的祖父母,充满了父母,这是充满了孩子。

原因没有更多的祖父母会被发现是因为grandParent的id应该是唯一的,因为祖父母的referenceId只有祖父母的财产。

我希望我明确指出了自己的观点,因为通过这种方法,人们可以轻松地搜索一个特定的孩子,通过参考ID轻松获取其父母,并通过参考ID轻松获得其父母。

这可能有点复杂,但是一旦你为自己想出了方法,它的所有方面都很简单。

Hylke

+0

在YouTube上的一些相关视频,其中一个关于[“基数最低原则”](https://www.youtube.com/watch?v=L994ZiVuSTE),另一个关于[存储分层数据]示例(https ://www.youtube.com/watch v = T5Yt6Ndm2QY)。这来自一个关于EDX的Mongoose相关课程,名为[“使用MEAN栈介绍MongoDB”](https://courses.edx.org/courses/course-v1:MongoDBx+M101x+3T2015/info) – 2015-12-25 05:52:13

2

是非常困难的事情在一个干净的方式工作,得到这样。

我没有在这个主题上找到一个干净的解决方案,但也许我可以帮助你循环的事情。 您可以使用以下方式避免循环: var doc = parent.children.id(id); Finding a sub-document

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

+0

但在这种情况下,我第一次获得大文件,然后我从这个文件,我需要的所有字段选择。相反,我只得到一个小的文件。我认为使用大文档处理小文档会更快。 – 2013-10-24 11:49:52

0

这个工作对我来说

 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 (projection)