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、Parent ID、子 ID、GrandChildID 和 GrandGrandChild ID,我想以某种方式只获取所有这些 ID 指向的 GrandGrandChild 对象。

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

我的问题是,我将如何在猫鼬中编写一个查询,该查询要么仅返回孙子文档,要么仅返回包含子属性的祖父文档,并且在该子属性中,仅包含引用子对象的父对象引用孙对象的孙对象,允许以下结果:

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);

这个查询的问题是没有修剪掉不必要的兄弟姐妹。

我希望有人可以帮助我。

希尔克·布朗

4

3 回答 3

3

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

在这种情况下,我将展示它如何仅与 GrandParent、Parent 和 Child 一起使用。

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

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
});

请注意,父级并不直接知道其父级,因为它们没有存储为子文档。然而,Parent 和 Child 之间仍然存在通过 referenceId 的连接。

在搜索 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
       });

     });
});

上面的代码将导致只有一个祖父母,其中充满了父母,而父母则充满了孩子。

找不到更多祖父母的原因是因为祖父母的 id 应该是唯一的,因为祖父母的 referenceId 只有祖父母属性。

我希望我的观点清楚,因为通过这种方法,人们可以轻松地搜索一个特定的孩子,通过参考 id 轻松获得其父母,也通过参考 id 获得其祖父母。

这可能有点复杂,但是一旦你自己弄清楚了方法,它就很简单了。

希尔克

于 2014-02-20T10:03:23.617 回答
2

很难让这种事情以一种干净的方式工作。

我没有找到关于这个主题的干净解决方案,但也许我可以帮助你解决循环问题。您可以使用以下方法避免循环: var doc = parent.children.id(id); 查找子文档

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

于 2013-06-26T15:38:54.620 回答
1

这对我有用

      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(投影)

于 2017-01-05T14:27:37.863 回答