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

时间:2022-05-26 21:26:46

I have a similar datastructure as this:

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

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

These are a lot of collections with subdocuments in them. Note that the ID's are unique to their siblings, but not unique to all elements with that same schema.

这些是包含子文档的很多集合。请注意,ID对于其兄弟姐妹是唯一的,但并非对具有相同模式的所有元素唯一。

So one grand parent can have an parent with id 0, and another grandparent can also have a parent with id 0. but one grandparent can not have 2 parents with id 0.

因此,一个祖父母可以拥有身份0的父母,另一个祖父母也可以拥有身份0的父母,但是一个祖父母不能拥有2个身份0的父母。

The only schema that gets saved is the GrandParent schema, and mongoose/mongodb makes a nice big single document of all the data of this grandparent. (Exactly what i am looking for)

保存的唯一模式是GrandParent模式,而mongoose / mongodb是这个祖父母的所有数据的一个很好的单个大文档。 (正是我要找的)

So here is my issue: I have a GrandParent ID, Parent ID, Child ID, GrandChildID and GrandGrandChild ID, and i want to somehow get only the GrandGrandChild object to which all these ID's are pointing.

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

The ugly way would be to, but currently the only way i can get to work, is to make a query that gets this big document of GrandParent, and manually loop through all arrays to find the right Parent, then loop again to find the right child, then loop again to find the right grandchild, then loop again and find the grandgrandchild im needing here.

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

My question is, how would i compose a query in mongoose that either returns only the grandgrandchild document, or the grandparent document with only the children attribute included, and in that children attribute only the parent object included that refers to the child object that refers to the grandchild object that refers to the grandgrandchild object, allowing the following with the result:

我的问题是,如何在mongoose中编写一个只返回grandgrandchild文档的查询,或者只包含children属性的祖父文档,并且在children子属性中只包含引用的子对象所包含的父对象引用grandgrandchild对象的孙子对象,允许以下结果:

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

I hope someone can help me on this query, as far is i got is this:

我希望有人可以帮我解决这个问题,因为我得到的是:

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

The problem with this query is that the unnessicary siblings arent trimmed away.

这个问题的问题在于,不合情理的兄弟姐妹没有被修剪掉。

I hope someone can help me out.

我希望有人可以帮助我。

Hylke Bron

3 个解决方案

#1


3  

it has been some time since I asked this question, but I think I found a rather elegant way of working with these kind of structures.

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

In this case I'll show how it works with only GrandParent, Parent and Child.

在这种情况下,我将展示它如何仅适用于GrandParent,Parent和Child。

Instead of storing a list of subdocuments in each document (GrandParent.children, Parent.children), I created an unique identifier of the following structure:

我没有在每个文档(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"
}

This creates a hierarchy of GrandParent > Parent > Child.

这将创建GrandParent> Parent> Child的层次结构。

The models would be something like the following:

模型将如下所示:

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

Notice that a Parent doesnt directly knows its parent, for they are not stored as subdocuments. Yet there still is a connection between Parent and Child, through the referenceId.

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

When searching for the whole familytree of a GrandParent, one would simply execute 3 queries, and then connect them correctly:

在搜索GrandParent的整个familytree时,只需执行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
       });

     });
});

The code above would result in just ONE grandparent, filled with parents, which are filled with children.

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

The reason no more grandparents would be found is because the id of the grandParent should be unique, for the referenceId of the grandparent only has a grandparent property.

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

I hope i made my point clear, because through this method, one can easily search for one specific child, easily get its parent through the reference id, and its grandparent also through the reference id.

我希望我明确指出,因为通过这种方法,人们可以轻松地搜索一个特定的孩子,通过引用ID轻松获取其父级,并通过引用ID轻松获取其祖父母。

It might be a bit complex, but once you figure the method out for yourself, its all kinda straight forward.

它可能有点复杂,但是一旦你为自己想出这个方法,它就会直截了当。

Hylke

#2


2  

Is very difficult to get this kind of things work in a clean way.

很难让这种东西以干净的方式运作。

I didn't find a clean solution on this topic, but maybe I can help you with the looping thing. You can avoid the loop using: var doc = parent.children.id(id); Finding a sub-document

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

I hope this help you. Regards, Sebastian.

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

#3


0  

this worked for me

这对我有用

      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)

#1


3  

it has been some time since I asked this question, but I think I found a rather elegant way of working with these kind of structures.

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

In this case I'll show how it works with only GrandParent, Parent and Child.

在这种情况下,我将展示它如何仅适用于GrandParent,Parent和Child。

Instead of storing a list of subdocuments in each document (GrandParent.children, Parent.children), I created an unique identifier of the following structure:

我没有在每个文档(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"
}

This creates a hierarchy of GrandParent > Parent > Child.

这将创建GrandParent> Parent> Child的层次结构。

The models would be something like the following:

模型将如下所示:

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

Notice that a Parent doesnt directly knows its parent, for they are not stored as subdocuments. Yet there still is a connection between Parent and Child, through the referenceId.

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

When searching for the whole familytree of a GrandParent, one would simply execute 3 queries, and then connect them correctly:

在搜索GrandParent的整个familytree时,只需执行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
       });

     });
});

The code above would result in just ONE grandparent, filled with parents, which are filled with children.

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

The reason no more grandparents would be found is because the id of the grandParent should be unique, for the referenceId of the grandparent only has a grandparent property.

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

I hope i made my point clear, because through this method, one can easily search for one specific child, easily get its parent through the reference id, and its grandparent also through the reference id.

我希望我明确指出,因为通过这种方法,人们可以轻松地搜索一个特定的孩子,通过引用ID轻松获取其父级,并通过引用ID轻松获取其祖父母。

It might be a bit complex, but once you figure the method out for yourself, its all kinda straight forward.

它可能有点复杂,但是一旦你为自己想出这个方法,它就会直截了当。

Hylke

#2


2  

Is very difficult to get this kind of things work in a clean way.

很难让这种东西以干净的方式运作。

I didn't find a clean solution on this topic, but maybe I can help you with the looping thing. You can avoid the loop using: var doc = parent.children.id(id); Finding a sub-document

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

I hope this help you. Regards, Sebastian.

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

#3


0  

this worked for me

这对我有用

      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)