集成在两个集合之间

时间:2017-03-21 11:27:36

标签: javascript mongodb mongodb-query aggregation-framework

我有两个系列:

'DBVisit_DB':

"_id" : ObjectId("582bc54958f2245b05b455c6"),
"visitEnd" : NumberLong(1479252157766),
"visitStart" : NumberLong(1479249815749),
"fuseLocation" : {....    }
"userId" : "A926D9E4853196A98D1E4AC6006DAF00@1927cc81cfcf7a467e9d4f4ac7a1534b",
"modificationTimeInMillis" : NumberLong(1479263563107),
"objectId" : "C4B4CE9B-3AF1-42BC-891C-C8ABB0F8DC40",
"creationTime" : NumberLong(1479252167996),
"lastUserInteractionTime" : NumberLong(1479252167996)

}

'device_data':

"_id" : { "$binary" : "AN6GmE7Thi+Sd/dpLRjIilgsV/4AAAg=", "$type" : "00" },
"auditVersion" : "1.0",
"currentTime" : NumberLong(1479301118381),
"data" : {
    "networkOperatorName" : "Cellcom",...
},
"timezone" : "Asia/Jerusalem",
"collectionAlias" : "DEVICE_DATA",
"shortDate" : 17121,
"userId" : "00DE86984ED3862F9277F7692D18C88A@1927cc81cfcf7a467e9d4f4ac7a1534b"

在DBVisit_DB中,我需要仅显示超过1小时的Cellcom用户的所有访问。 (visitEnd - visitStart> 1小时)。通过匹配两个集合中的userId值。 这就是我到目前为止所做的:

//create an array that contains all the rows that "Cellcom" is their networkOperatorName
    var users = db.device_data.find({  "data.networkOperatorName": "Cellcom" },{ userId: 1, _id: 0}).toArray();

//create an array that contains all the rows that the visit time is more then one hour
        var time = db.DBVisit_DB.find( { $where: function() { 
          timePassed = new Date(this.visitEnd - this.visitStart).getHours();
          return timePassed > 1}},
          { userId: 1, _id: 0, "visitEnd" : 1, "visitStart":1} ).toArray();

//merge between the two arrays
        var result = [];
        var i, j;
        for (i = 0; i < time; i++) {
            for (j = 0; j < users; j++) {
                if (time[i].userId == users[j].userId) {
                    result.push(time[i]);
                }
            }
        }

        for (var i = 0; i < result.length; i++) {
           print(result[i].userId);
        }

但它没有显示任何内容,尽管我确信在我创建的数组中都可以找到id。 *用于验证:我不是100%确定我正确计算了访问时间。 顺便说一下,我是javaScript和mongodb的新手

                          ********update********
在“device_data”中有不同的行但具有相同的“userId”字段。 在“device_data”中,我还有“data.networkOperatorName”字段,其中包含不同类型的蜂窝公司。 我被要求显示所有基于'DBVisit_DB'集合的“Cellcom”用户连接超过一小时的意思, 基于“visitEnd”和“visitStart”字段,我需要知道是否(“visitEnd” - “visitStart”&gt; 1)

    {  "userId" : "457A7A0097F83074DA5E05F7E05BEA1D@1927cc81cfcf7a467e9d4f4ac7a1534b" }
{  "userId" : "E0F5C56AC227972CFAFC9124E039F0DE@1927cc81cfcf7a467e9d4f4ac7a1534b" }
{  "userId" : "309FA12926EC3EB49EB9AE40B6078109@1927cc81cfcf7a467e9d4f4ac7a1534b" }
{  "userId" : "B10420C71798F1E8768ACCF3B5E378D0@1927cc81cfcf7a467e9d4f4ac7a1534b" }
{  "userId" : "EE5C11AD6BFBC9644AF3C742097C531C@1927cc81cfcf7a467e9d4f4ac7a1534b" }
{  "userId" : "20EA1468672EFA6793A02149623DA2C4@1927cc81cfcf7a467e9d4f4ac7a1534b" }

每个数组都包含这种格式,在我的查询之后,我需要将它们合并为一个。我会有他们之间的交集。

非常感谢所有的帮助!

2 个答案:

答案 0 :(得分:1)

使用聚合框架,您可以通过使用 $lookup 运算符来实现所需的结果,该运算符允许您执行&#34; left-join&#34;对同一数据库中的集合进行操作,并利用 $redact 管道运算符,该运算符可以容纳操作时间戳的算术运算符,并将它们转换为可以查询的分钟数。

要显示上述聚合运算符的实用程度的简单示例,您可以在DBVisit_DB集合上运行以下管道,以分钟为单位查看实际时差:

db..getCollection('DBVisit_DB').aggregate([
    {
        "$project": {
             "visitStart": { "$add": [ "$visitStart", new Date(0) ] },
             "visitEnd": { "$add": [ "$visitEnd", new Date(0) ] },
             "timeDiffInMinutes": { 
                "$divide": [
                    { "$subtract": ["$visitEnd", "$visitStart"] }, 
                    1000 * 60
                ] 
            },
            "isMoreThanHour": {
                "$gt": [
                    { 
                        "$divide": [
                            { "$subtract": ["$visitEnd", "$visitStart"] }, 
                            1000 * 60
                        ] 
                    }, 60
                ]
            }
        }
    }
])

示例输出

{
    "_id" : ObjectId("582bc54958f2245b05b455c6"),
    "visitEnd" : ISODate("2016-11-15T23:22:37.766Z"),
    "visitStart" : ISODate("2016-11-15T22:43:35.749Z"),
    "timeDiffInMinutes" : 39.0336166666667,
    "isMoreThanHour" : false
}

现在,了解上述运算符的工作原理,现在可以在以下示例中应用它,其中运行以下聚合管道将使用device_data集合作为主集合,首先过滤文档使用 $match 指定字段,然后使用 $lookup 加入DBVisit_DB集合。 $redact 将处理在 $cond 内获取超过一小时的访问的逻辑条件,并使用特殊系统变量 { {3}} to&#34; keep&#34;逻辑条件为真的文档或 $$KEEP 到&#34; discard&#34;条件错误的文件。

算术运算符 $$PRUNE $divide 允许您计算两个时间戳字段之间的差异,以及 $subtract 逻辑运算符然后评估条件:

db.device_data.aggregate([
    /* Filter input documents */
    { "$match": { "data.networkOperatorName": "Cellcom" } },

    /* Do a left-join to DBVisit_DB collection */
    {
        "$lookup": {
            "from": "DBVisit_DB",
            "localField": "userId",
            "foreignField": "userId",
            "as": "userVisits"
        }
    },

    /* Flatten resulting array */
    { "$unwind": "$userVisits" },

    /* Redact documents */
    {
        "$redact": {
            "$cond": [
                {
                    "$gt": [
                        { 
                            "$divide": [
                                { "$subtract": [
                                        "$userVisits.visitEnd", 
                                        "$userVisits.visitStart"
                                ] }, 
                                1000 * 60
                            ] 
                        },
                        60
                    ]
                },
                "$$KEEP",
                "$$PRUNE"
            ]
        }
    }
])

答案 1 :(得分:1)

您的java脚本中有一些不正确的东西。

time循环中将userstime.length条件替换为users.lengthfor

您的timePassed计算应为

timePassed = this.visitEnd - this.visitStart
      return timePassed > 3600000

您有几个与数据相关的问题。

您没有匹配的userIdvisitEndvisitStart之间的差异不到一小时,您在问题中发布的文件就不会有。

对于基于mongo的查询,您应该结帐其他answer

相关问题