【问题标题】:Finding documents with $in, using an array of another document使用 $in 查找文档,使用另一个文档的数组
【发布时间】:2019-07-28 03:51:09
【问题描述】:

我正在尝试使用 Meteor.js、Blaze 和 Mongodb 构建一个友谊系统。我现在想在他的个人资料页面上显示用户的朋友。

我有一个集合“users”,其中包含字段“friends”,这是一个可以推入或拉出其他用途名称的数组。

用户文档的简化示例:

"name" : "bob"
"friends" : ["value of name-field of user-document1", "value of name-field of user-document2", "etc."]

我尝试将这个朋友数组放在配置文件的隐藏输入中,并从那里使用它在 profile-template.helpers 上创建迭代:

<input id="friends" type="hidden" value="{{user.friends}}">
  friends() {
      var friends = document.getElementById("friends").value;
      var friendsArray = friends.split(",");
      return Users.find({name:{$in: friendsArray},})
     }, 

但这不是它的工作原理。如何使用/获取此字段,其中包含此 $in 操作的好友数组,以获取与 bob 成为好友的其他用户?我也试过 this.friends 但这似乎只适用于迭代。

我可以使用

{{#each friend in user.friends}}
{{friend}}
{{/each}}

至少要得到朋友的名字,但我想在显示朋友部分也包括那些朋友的小头像,所以那不行。

编辑:用户变量在 Template.user.helpers 中定义为:

  user: ()=> { 
    var user = FlowRouter.getParam('user');
    return Users.findOne({name: user});
  },

我尝试在朋友功能中使用this.data.char.friends,就像这样

  friends() {
   return Users.find({
   name: { $in: (this.data.user.friends) }
    });
},

但它给了我一个 console.log 错误:

Exception in template helper: ReferenceError: user is not defined

【问题讨论】:

  • 在您的 Blaze 模板中,您正在使用 &lt;input id="friends" type="hidden" value="{{user.friends}}"&gt; - user 变量是如何定义的?在您的模板助手friends 中,您最好执行this.data.user.friends 之类的操作(=从模板数据上下文中获取值),而不是从呈现的输入字段中获取该值。
  • 如果我在同一个 template.user.helpers 中有两个变量(friends() 和 user:),我还能使用“this.data.user.friends”吗?我试着把它放进去,但它给了我一个错误^
  • @TKur :好的,基本上你想根据来自 mongoDB 的给定用户获取朋友数组中列出的每个人的详细信息?用户的朋友数组中列出的人是否在同一个集合中拥有自己的记录/数据/文档,并且具有唯一 ID,例如姓名/某物??
  • 是的,这就是我想要的。朋友数组中列出的每个人本身在用户集合中都有自己的文档。当然,他们也有自己的 ID。但是保存在friendarray中的是该用户文档的名称字段。
  • @TKur :我已经给我的查询尝试过,并确保您从friendsDetails Array 中提取数据,以将朋友详细信息作为单个对象!

标签: mongodb meteor meteor-blaze


【解决方案1】:

试试这个聚合查询,而不是多次调用 DB 来获取所需的数据:

db.getCollection('Users').aggregate([{ $match: { name: 'bob' } },
{
    $graphLookup: {
        from: "Users",
        startWith: "$friends",
        connectFromField: "friends",
        connectToField: "name",
        as: "friendsDetails"
    }
}, { $project: { name: 1, friends: 1, friendsDetails: { $filter: { input: '$friendsDetails', as: 'item', cond: { $ne: ['$$item.name', 'bob'] } } } } }])

我们之所以使用$project$filter,默认情况下$graphLookup 将在friendsDetails 列表中返回请求的用户,使用这些将其从最终结果中删除。

【讨论】:

    【解决方案2】:

    啊不,实际上比那更简单。

      friends() {
        var name = FlowRouter.getParam('user');
        return Users.find( { friends: { $in: [name] } } );
    },
    

    这个显示个人资料上的朋友就是这样。我只需要弄清楚它为什么会这样......

    【讨论】:

    • 是的,它很简单,很好,但是在您的流程的任何情况下,您都不需要返回实际用户(bob)的文档(在这种情况下,添加名称:'bob' 来查询)?而且您最初的问题与获取朋友列表并将其存储在某处然后检索朋友详细信息不同。还找到这样的查询在技术上扫描每个文档以查找给定名称以在朋友列表中,除非正确索引 vs $graphLookup 只需要索引名称并快速获取精确匹配。所以结果是朋友作为数组(Vs)名称作为要索引的字符串,只需检查(n-1 vs 1-1)
    • 问题并没有改变。我试图实现的确实是检索保存在该好友数组中的那些用户的文档。这种方式对我有用。我之前尝试过你的建议,但对我没有用。它已经在 getCollection 上失败了——在 Meteor 中,某些语法细节在某些领域似乎有所不同。但是,bob 文档将已经返回,因为它位于正在显示朋友的配置文件中。除了简单的东西,我很想学习更多 mongodb 的方法,但现在我对这个结果很满意,谢谢。
    • 好的,注册。 '它已经在 getCollection 上失败' - 这是一种数据库语法,您不会在代码中使用它,即;当您已经定义了一个您将使用该“User.aggregate”的模型时,它是流星还是其他任何东西都没有关系。我一定已经预料到我需要给出准确的代码(我给出的是一个聚合查询来获得结果),好吧,当它工作时很酷,快乐的编码。
    猜你喜欢
    • 2015-01-14
    • 2014-01-25
    • 2020-10-09
    • 1970-01-01
    • 2020-06-11
    • 2017-06-24
    • 2021-08-14
    • 2018-10-26
    • 1970-01-01
    相关资源
    最近更新 更多