SlideShare a Scribd company logo
1 of 73
# M D B l o c a l
ASYA KAMSKY
LEAD KNOW-IT-ALL MONGODB, INC @asya999 #askAsya
PIPELINE POWER
ANALYTICS WITH MONGODB AGGREGATION
FRAMEWORK
APPLICATIONS & DATA
STORE
RETRIEVE
#MDBTOUR
Options for analytics
pre-aggregate
aggregate
in MongoDB
aggregate elsewhere
#MDBTOUR
Options for analytics
pre-aggregate
aggregate
in MongoDB
aggregate elsewhere
#MDBTOUR
Options for analytics
pre-aggregate
aggregate
in MongoDB
aggregate elsewhere
#MDBW17
Options for analytics
pre-aggregate
aggregate
in MongoDB
aggregate elsewhere
#MDBW17
Options for analytics
pre-aggregate
aggregate
in MongoDB
aggregate elsewhere
#MDBW17
analytics = Aggregation
pre-aggregate
aggregate
in MongoDB
aggregate elsewhere
#MDBW17
PIPELINE
ps ax |grep mongod |head 1
*nix command line pipe
PIPELINE
$match $group | $sort|
Input stream {} {} {}{} Result {} {}...
PIPELINE
MongoDB document pipeline
Stage 1 Stage 2 Stage 3 Stage 4
{}{}{}{}
{}{}{}{}
DATA PIPELINE
{}{}{}{}
{"$stage":{ ... }}
START
Collection
View
Special stage
{title: "The Great Gatsby",
language: "English",
subjects: "Long Island"}
{title: "The Great Gatsby",
language: "English",
subjects: "New York"}
{title: "The Great Gatsby",
language: "English",
subjects: "1920s"}
{title: "The Great Gatsby",
language: "English",
subjects: [
"Long Island",
"New York",
"1920s"] },
{"$match":{"language":"English"}}
$match
{ _id:"Long Island",
count: 1 },
$group
{ _id: "New York",
count: 2 },
$unwind
{ _id: "1920s",
count: 1 },
$sort $skip$limit $project
{"$unwind":"$subjects"}
{"$group":{"_id":"$subjects", "count":{"$sum:1}}
{ _id: "Harlem",
count: 1 },
{ _id: "Long Island",
count: 1 },
{ _id: "New York",
count: 2 },
{ _id: "1920s",
count: 1 },
{title: "Open City",
language: "English",
subjects: [
"New York"
"Harlem" ] }
{ title: "The Great Gatsby",
language: "English",
subjects: [
"Long Island",
"New York",
"1920s"] },
{ title: "War and Peace",
language: "Russian",
subjects: [
"Russia",
"War of 1812",
"Napoleon"] },
{ title: "Open City",
language: "English",
subjects: [
"New York",
"Harlem" ] },
{title: "Open City",
language: "English",
subjects: "New York"}
{title: "Open City",
language: "English",
subjects: "Harlem"}
{ _id: "Harlem",
count: 1 },
{"$sort:{"count":-1} {"$limit":3}
{"$project":...}
Group and
Transform
Aliases
Special
•Input
•Output
Reorder
Transform
Decrease
Increase
{title: "The Great Gatsby",
language: "English".
subjects: "Long Island"}
{title: "The Great Gatsby",
language: "English",
subjects: "New York"}
{title: "The Great Gatsby",
language: "English",
subjects: "1920s"}
{title: "The Great Gatsby",
language: "English",
subjects: [
"Long Island",
"New York",
"1920s"] },
{"$match":{"language":"English"}}
$match
{ _id:"Long Island",
count: 1 },
$group
{ _id: "New York",
count: 2 },
$unwind
{ _id: "1920s",
count: 1 },
$sort $skip$limit $project
{"$unwind":"$subjects"}
{"$group":{"_id":"$subjects", "count":{"$sum:1}}
{ _id: "Harlem",
count: 1 },
{ _id:"LongIsland",
count: 1 },
{ _id: "New York",
count: 2 },
{ _id: "1920s",
count: 1 },
{title: "Open City",
language: "English",
subjects: [
"New York"
"Harlem" ] }
{ title: "The Great Gatsby",
language: "English",
subjects: [
"Long Island",
"New York",
"1920s"] },
{ title: "War and Peace",
language: "Russian",
subjects: [
"Russia",
"War of 1812",
"Napoleon"] },
{ title: "Open City",
language: "English",
subjects: [
"New York",
"Harlem" ] },
{title: "Open City",
language: "English",
subjects: "New York"}
{title: "Open City",
language: "English",
subjects: "Harlem"}
{ _id: "Harlem",
count: 1 },
{"$sort:{"count":-1} {"$limit":3}
{"$project":...}
$group $sort
1
Group and
Transform
Aliases
Special
•Input
•Output
Reorder
Transform
Decrease
Increase
$group
$sort
#MDBTOUR
LET ME EXPLAIN...
db.books.aggregate([
{$match:{"language":"English"}},
{$unwind:"$subjects"},
{$group:{_id:"$subjects",count:{$sum:1}}},
{$sort:{count:-1}},
{$limit:3}
],{explain:true})
{"stages" : [
{"$cursor" : {"query" : { "language" : "English"},
"fields" : { "subjects" : 1,"_id" : 0} ...
}},
{"$unwind" : {"path" : "$subjects"}},
{"$group" : {"_id" : "$subjects","count" : {"$sum" : {"$const" : 1}} }},
{"$sort" : {
"sortKey" : {"count" : -1},
"limit" : NumberLong(3)
}}
] }
db.books.aggregate([
{$match:{"language":"English"}},
{$unwind:"$subjects"},
{$group:{_id:"$subjects",count:{$sum:1}}},
{$sort:{count:-1}},
{$limit:3}
],{explain:true})
{"stages" : [
{"$cursor" : {"query" : { "language" : "English"},
"fields" : { "subjects" : 1,"_id" : 0} ...
}},
{"$unwind" : {"path" : "$subjects"}},
{"$group" : {"_id" : "$subjects","count" : {"$sum" : {"$const" : 1}} }},
{"$sort" : {
"sortKey" : {"count" : -1},
"limit" : NumberLong(3)
}}
] }
db.books.aggregate([
{$match:{"language":"English"}},
{$unwind:"$subjects"},
{$group:{_id:"$subjects",count:{$sum:1}}},
{$sort:{count:-1}},
{$limit:3}
],{explain:true})
{"stages" : [
{"$cursor" : {"query" : { },
"fields" : { "subjects" : 1,"_id" : 0} ...
}},
{"$unwind" : {"path" : "$subjects"}},
{"$group" : {"_id" : "$subjects","count" : {"$sum" : {"$const" : 1}} }},
{"$sort" : {
"sortKey" : {"count" : -1},
"limit" : NumberLong(3)
}}
] }
db.books.aggregate([
{$unwind:"$subjects"},
{$match:{"language":"English"}},
{$group:{_id:"$subjects",count:{$sum:1}}},
{$sort:{count:-1}},
{$limit:3}
],{explain:true})
db.books.aggregate([
{$unwind:"$subjects"},
{$match:{"language":"English"}},
{$group:{_id:"$subjects",count:{$sum:1}}},
{$sort:{count:-1}},
{$limit:3}
],{explain:true})
{"stages" : [
{"$cursor" : {"query" : { "language" : "English"},
"fields" : { "subjects" : 1,"_id" : 0} ...
}},
{"$unwind" : {"path" : "$subjects"}},
{"$group" : {"_id" : "$subjects","count" : {"$sum" : {"$const" : 1}} }},
{"$sort" : {
"sortKey" : {"count" : -1},
"limit" : NumberLong(3)
}}
] }
db.books.aggregate([
{$unwind:"$subjects"},
{$match:{"language":"English","subjects":/^[ABC]/}},
{$group:{_id:"$subjects",count:{$sum:1}}},
{$sort:{count:-1}},
{$limit:3}
],{explain:true})
{"stages" : [
{"$cursor" : {"query" : { "language" : "English"},
"fields" : { "subjects" : 1,"_id" : 0} ...
}},
{"$unwind" : {"path" : "$subjects"}},
{"$match" : {"subjects" : {"$regex" : "^[ABC]"}}},
{"$group" : {"_id" : "$subjects","count" : {"$sum" : {"$const" : 1}}}},
{"$sort" : {
"sortKey" : {"count" : -1},
"limit" : NumberLong(3)
}}
] }
db.books.aggregate([
{$unwind:"$subjects"},
{$match:{"language":"English","subjects":/^[ABC]/}},
{$group:{_id:"$subjects",count:{$sum:1}}},
{$sort:{count:-1}},
{$limit:3}
],{explain:true})
{"stages" : [
{"$cursor" : {"query" : { "language" : "English"},
"fields" : { "subjects" : 1,"_id" : 0} ...
}},
{"$unwind" : {"path" : "$subjects"}},
{"$match" : {"subjects" : {"$regex" : "^[ABC]"}}},
{"$group" : {"_id" : "$subjects","count" : {"$sum" : {"$const" : 1}}}},
{"$sort" : {
"sortKey" : {"count" : -1},
"limit" : NumberLong(3)
}}
] }
#MDBTOUR
EXAMPLES
#MDBTOUR
SCHEMA DISCOVERY & TRANSFORMATION
{"body": {
"VMESSAGE": {
"072ade7d42d8": {
"msgId": "bcd1d9",
"date":1486546629585,
"status": "accept",
"comment": "hi"
} } } },
{"body": {
"VMESSAGE": {
"595d0a56cff2": {
"msgId": "595d0a",
"date":1486566646197,
"status": "reject",
"comment": "no good"
} } } },
{ "body": {
"VMESSAGE": {
"52ffd09bf5b5": {
"msgId": "1dadce",
"date":1486568943752,
"status": "accept"
} } } }
$project $addFields
{"message": {
"vid": "072ade7d42d8",
"msgId": "bcd1d9",
"date": 1486546629585,
"status": "accept",
"comment": "hi"
} },
{"message": {
"vid": "595d0a56cff2",
"msgId": "595d0a",
"date": 1486566646197,
"status": "reject",
"comment": "no good"
} },
{"message": {
"vid": "52ffd09bf5b5",
"msgId": "1dadce",
"date": 1486568943752,
"status": "accept"
} }
{"body": {
"VMESSAGE": {
"072ade7d42d8": {
"msgId": "bcd1d9",
"date":1486546629585,
"status": "accept",
"comment": "hi"
} } } },
{"body": {
"VMESSAGE": {
"595d0a56cff2": {
"msgId": "595d0a",
"date":1486566646197,
"status": "reject",
"comment": "no good"
} } } },
{ "body": {
"VMESSAGE": {
"52ffd09bf5b5": {
"msgId": "1dadce",
"date":1486568943752,
"status": "accept"
} } } }
$addFields
New Expressions (3.4.4, 3.6):
{"$objectToArray": <object>}
=> array of k/v pairs
{"$arrayToObject": <array of k/v pairs>}
=> object
{"message": {
"vid": "072ade7d42d8",
"msgId": "bcd1d9",
"date": 1486546629585,
"status": "accept",
"comment": "hi"
} },
{"message": {
"vid": "595d0a56cff2",
"msgId": "595d0a",
"date": 1486566646197,
"status": "reject",
"comment": "no good"
} },
{"message": {
"vid": "52ffd09bf5b5",
"msgId": "1dadce",
"date": 1486568943752,
"status": "accept"
} }
Object "body.VMESSAGE":
{
"072ade7d42d8": {
"messageId": "bcd1d9",
"date": 1486546629585,
"status": "accept",
"comment": "hi"
} }
$ObjectToArray:"$body.VMESSAGE"
[ {
"k":"072ade7d42d8",
"v": {
"messageId": "bcd1d991",
"date": 1486546629585,
"status": "accept",
"comment": "hi"
} }
]
Need array: [
{"k":"vid", "v":"072ade7d42d8"},
{"k":"messageId", "v":"bcd1d9"},
{"k":"date", "v":1486546629585,
{"k":"status", "v":"accept"},
{"k":"comment", "v":"hi"}
]
{"$addFields": {
"message": {
"$arrayToObject":
...
{"$objectToArray":"$body.VMESSAGE"}
}
} }
$addFields
{"body": {
"VMESSAGE": {
"072ade7d42d8": {
"msgId": "bcd1d9",
"date":1486546629585,
"status": "accept",
"comment": "hi"
} } } },
{"body": {
"VMESSAGE": {
"595d0a56cff2": {
"msgId": "595d0a",
"date":1486566646197,
"status": "reject",
"comment": "no good"
} } } },
{ "body": {
"VMESSAGE": {
"52ffd09bf5b5": {
"msgId": "1dadce",
"date":1486568943752,
"status": "accept"
} } } }
{"message": {
"vid": "072ade7d42d8",
"msgId": "bcd1d9",
"date": 1486546629585,
"status": "accept",
"comment": "hi"
} },
{"message": {
"vid": "595d0a56cff2",
"msgId": "595d0a",
"date": 1486566646197,
"status": "reject",
"comment": "no good"
} },
{"message": {
"vid": "52ffd09bf5b5",
"msgId": "1dadce",
"date": 1486568943752,
"status": "accept"
} }
{"$addFields": {
"bvm": {"$objectToArray":"$body.VMESSAGE"}
} },
$addFields$addFields
{"$addFields": {
"msgarr": {
}
} },
{"$addFields": {
"message": {"$arrayToObject": "$msgarr"}
} }
{"$addFields": {
"bvm2": {"$arrayElemAt":["$bvm",0]}
} },
{"$addFields": {
"bvm": {"$objectToArray":"$bvm2.v"}
} },
$addFields $addFields $addFields
{"body": {
"VMESSAGE": {
"072ade7d42d8": {
"msgId": "bcd1d9",
"date":1486546629585,
"status": "accept",
"comment": "hi"
} } } },
{"body": {
"VMESSAGE": {
"595d0a56cff2": {
"msgId": "595d0a",
"date":1486566646197,
"status": "reject",
"comment": "no good"
} } } },
{ "body": {
"VMESSAGE": {
"52ffd09bf5b5": {
"msgId": "1dadce",
"date":1486568943752,
"status": "accept"
} } } }
{"message": {
"vid": "072ade7d42d8",
"msgId": "bcd1d9",
"date": 1486546629585,
"status": "accept",
"comment": "hi"
} },
{"message": {
"vid": "595d0a56cff2",
"msgId": "595d0a",
"date": 1486566646197,
"status": "reject",
"comment": "no good"
} },
{"message": {
"vid": "52ffd09bf5b5",
"msgId": "1dadce",
"date": 1486568943752,
"status": "accept"
} }
{"$addFields": {
"bvm": {"$objectToArray":"$body.VMESSAGE"}
} },
$addFields$addFields
{"$addFields": {
"msgarr": {
"$concatArrays": [
[ { "k":"vid", "v":"$bvm2.k"} ],
"$bvm"
]
}
} },
{"$addFields": {
"message": {"$arrayToObject": "$msgarr"}
} }
{"$addFields": {
"bvm2": {"$arrayElemAt":["$bvm",0]}
} },
{"$addFields": {
"bvm": {"$objectToArray":"$bvm2.v"}
} },
$addFields $addFields $addFields
{"body": {
"VMESSAGE": {
"072ade7d42d8": {
"msgId": "bcd1d9",
"date":1486546629585,
"status": "accept",
"comment": "hi"
} } } },
{"body": {
"VMESSAGE": {
"595d0a56cff2": {
"msgId": "595d0a",
"date":1486566646197,
"status": "reject",
"comment": "no good"
} } } },
{ "body": {
"VMESSAGE": {
"52ffd09bf5b5": {
"msgId": "1dadce",
"date":1486568943752,
"status": "accept"
} } } }
{"message": {
"vid": "072ade7d42d8",
"msgId": "bcd1d9",
"date": 1486546629585,
"status": "accept",
"comment": "hi"
} },
{"message": {
"vid": "595d0a56cff2",
"msgId": "595d0a",
"date": 1486566646197,
"status": "reject",
"comment": "no good"
} },
{"message": {
"vid": "52ffd09bf5b5",
"msgId": "1dadce",
"date": 1486568943752,
"status": "accept"
} }
$addFields
{"$addFields":{
"message":{
"$arrayToObject":{
"$let":{
"vars":{
"elem": {"$arrayElemAt:[
{"$objectToArray":"$body.VMESSAGE"},
0
]}
},
"in":{"$concatArrays":[
[ { k: "vid", v: "$$elem.k" } ],
{$objectToArray:"$$elem.v"}
]}
}}
}
}}
{"body": {
"VMESSAGE": {
"072ade7d42d8": {
"msgId": "bcd1d9",
"date":1486546629585,
"status": "accept",
"comment": "hi"
} } } },
{"body": {
"VMESSAGE": {
"595d0a56cff2": {
"msgId": "595d0a",
"date":1486566646197,
"status": "reject",
"comment": "no good"
} } } },
{ "body": {
"VMESSAGE": {
"52ffd09bf5b5": {
"msgId": "1dadce",
"date":1486568943752,
"status": "accept"
} } } }
{"message": {
"vid": "072ade7d42d8",
"msgId": "bcd1d9",
"date": 1486546629585,
"status": "accept",
"comment": "hi"
} },
{"message": {
"vid": "595d0a56cff2",
"msgId": "595d0a",
"date": 1486566646197,
"status": "reject",
"comment": "no good"
} },
{"message": {
"vid": "52ffd09bf5b5",
"msgId": "1dadce",
"date": 1486568943752,
"status": "accept"
} }
$addFields
{"$addFields":{
"message":{
"$arrayToObject":{
"$let":{
"vars":{
"elem": {"$arrayElemAt:[
{"$objectToArray":"$body.VMESSAGE"},
0
]}
},
"in":{"$concatArrays":[
[ { k: "vid", v: "$$elem.k" } ],
{$objectToArray:"$$elem.v"}
]}
}}
}
}}
{"body": {
"VMESSAGE": {
"072ade7d42d8": {
"msgId": "bcd1d9",
"date":1486546629585,
"status": "accept",
"comment": "hi"
} } } },
{"body": {
"VMESSAGE": {
"595d0a56cff2": {
"msgId": "595d0a",
"date":1486566646197,
"status": "reject",
"comment": "no good"
} } } },
{ "body": {
"VMESSAGE": {
"52ffd09bf5b5": {
"msgId": "1dadce",
"date":1486568943752,
"status": "accept"
} } } }
{"message": {
"vid": "072ade7d42d8",
"msgId": "bcd1d9",
"date": 1486546629585,
"status": "accept",
"comment": "hi"
} },
{"message": {
"vid": "595d0a56cff2",
"msgId": "595d0a",
"date": 1486566646197,
"status": "reject",
"comment": "no good"
} },
{"message": {
"vid": "52ffd09bf5b5",
"msgId": "1dadce",
"date": 1486568943752,
"status": "accept"
} }
$addFields
{"$addFields":{
"message":{
"$arrayToObject":{
"$let":{
"vars":{
"elem": {"$arrayElemAt:[
{"$objectToArray":"$body.VMESSAGE"},
0
]}
},
"in":{"$concatArrays":[
[ { k: "vid", v: "$$elem.k" } ],
{$objectToArray:"$$elem.v"}
]}
}}
}
}}
{"body": {
"VMESSAGE": {
"072ade7d42d8": {
"msgId": "bcd1d9",
"date":1486546629585,
"status": "accept",
"comment": "hi"
} } } },
{"body": {
"VMESSAGE": {
"595d0a56cff2": {
"msgId": "595d0a",
"date":1486566646197,
"status": "reject",
"comment": "no good"
} } } },
{ "body": {
"VMESSAGE": {
"52ffd09bf5b5": {
"msgId": "1dadce",
"date":1486568943752,
"status": "accept"
} } } }
{"message": {
"vid": "072ade7d42d8",
"msgId": "bcd1d9",
"date": 1486546629585,
"status": "accept",
"comment": "hi"
} },
{"message": {
"vid": "595d0a56cff2",
"msgId": "595d0a",
"date": 1486566646197,
"status": "reject",
"comment": "no good"
} },
{"message": {
"vid": "52ffd09bf5b5",
"msgId": "1dadce",
"date": 1486568943752,
"status": "accept"
} }
#MDBTOUR
ARRAY MANIPULATIONS
#MDBTOUR
array manipulations
$arrayElemAt
$concatArrays
$indexOfArray
$isArray
$size
$range
$reverseArray
$map
$reduce
$filter
$slice
$zip
$in
... plus all the set expressions
#MDBTOUR
array manipulations
$arrayElemAt
$concatArrays
$indexOfArray
$isArray
$size
$range
$reverseArray
$map
$reduce
$filter
$slice
$zip
$in
... plus all the set expressions
#MDBTOUR
array manipulations
$arrayElemAt
$concatArrays
$indexOfArray
$isArray
$size
$range
$reverseArray
$map
$reduce
$filter
$slice
$zip
$in
... plus all the set expressions
#MDBTOUR
array manipulations
$map
input: array
output: array
$filter
input: array
output: subset of array
$reduce
input: array
output: anything
you
want
#MDBTOUR
array manipulations:
"arr":[{"a":1},{"a":99},{"a":5},{"a":3}]
{"$map":{
"input":"$arr",
"in":"$$this"
}}
{"$map":{
"input":"$arr",
"as":"eachElem",
"in":{"b":"$$eachElem.a"}
}}
{"$map":{
"input":{"$range":[0,{"$size":"$arr"}]},
"as":"index",
"in":{"c":{"$arrayElemAt":["$arr.a","$$index"]}}
}}
"a" 1
"a" 99
"a" 5
"a" 3
"b" 1
"b" 99
"b" 5
"b" 3
"c" 1
"c" 99
"c" 5
"c" 3
"a" 1
"a" 99
"a" 5
"a" 3
"a" 1
"a" 99
"a" 5
"a" 3
0
1
2
3
{"$map":{
"input":"$arr",
"as":"var",
"in":"$$var" }}
$map
{"$map":{
"input":"$arr.a",
"as":"eachElem",
"in":{"b":"$$eachElem"}}}
1
99
5
3
#MDBTOUR
array manipulations:
"arr":[{"a":1},{"a":99},{"a":5},{"a":3}]
{"$filter":{
"input":"$arr",
"cond":{"$lt":["$$this.a",10]}
}}
{"$filter":{
"input":"$arr",
"as":"elem",
"cond":{"$lt":["$$elem.a",10]}
}}
"a" 1
"a" 99
"a" 5
"a" 3
$filter
"a" 1
"a" 5
"a" 3
#MDBTOUR
array manipulations:
"arr":[{"a":1},{"a":99},{"a":5},{"a":3}]
{"$reduce":{
"input":"$arr",
"initialValue": 0,
"in":{$add:["$$value","$$this.a"]}
}}
"a" 1
"a" 99
"a" 5
"a" 3
$reduce
01100105108
#MDBTOUR
array manipulations:
"arr":[{"a":1},{"a":99},{"a":5},{"a":3}]
{"$reduce":{
"input":"$arr",
"initialValue": 0,
"in":{$add:["$$value","$$this.a"]}
}}
{"$reduce":{
"input":"$arr",
"intialValue":[],
"in":{"$concatArrays":[
["$$this"],
"$$value"
]}
}}
$reduce
"a" 1
"a" 99
"a" 5
"a" 3
108
"a" 1
"a" 99
"a" 5
"a" 3
#MDBTOUR
array manipulations:
"arr":[{"a":1},{"a":99},{"a":5},{"a":3}]
{"$reduce":{
"input":"$arr",
"initialValue": 0,
"in":{$add:["$$value","$$this.a"]}
}}
{"$reduce":{
"input":"$arr",
"intialValue":[],
"in":{"$concatArrays":[
["$$this"],
"$$value"
]}
}}
$reduce
"a" 1
"a" 99
"a" 5
"a" 3
[]"a" 1"a" 99
"a" 1
"a" 5
"a" 99
"a" 1
"a" 3
"a" 5
"a" 99
"a" 1
108
"a" 1
"a" 99
"a" 5
"a" 3
#MDBTOUR
readability tip
#MDBTOUR
encapsulate complexity
Functions for expressions reverseArray=function(input){
return{"$reduce":{
"input":input,
"intialValue":[],
"in":{"$concatArrays":[
["$$this"],
"$$value"
]}
}};
};
db.c.aggregate([{"$addFields":{
"revArray":reverseArray("$origArray")
}}])
#MDBTOUR
encapsulate complexity
Functions for expressions
sortArray=function(inputArray,sortField="",asc=false)
{
varsuffix="";
varmaxF=MaxKey;
varminF=MinKey;
db.c.aggregate([{"$addFields":{
"sortedArray":sortArray("$origArray")
}}])
#MDBTOUR
network suspect activity detection
start=ISODate("...")
end=ISODate("...")
{
user: "303900",
ipaddr: "71.56.112.56",
ts:ISODate("2017-05-08T05:28:13Z")
}
{$match:{ts:{$gte:start,$lt:end}}},
{$sort:{ts:1}},
{$group:{_id:"$user",ips:{$push:{ip:"$ipaddr", ts:"$ts"}}}},
$sort$match $group
start=ISODate("...")
end=ISODate("...")
{
user: "303900",
ipaddr: "71.56.112.56",
ts:ISODate("2017-05-08T...")
}
{ _id: "303900",
ips: [
{ip:"71.56.112.56",
ts:ISODate("2017-05-08T08:54:04Z")
},
{ip:"71.56.112.56",
ts:ISODate("2017-05-09T09:01:11Z")
},
{ip:"12.130.117.87",
ts:ISODate("2017-05-09T09:04:59Z")
}
]}
$sort$match $group $addFields $match
start=ISODate("...")
end=ISODate("...")
{
user: "303900",
ipaddr: "71.56.112.56",
ts:ISODate("2017-05-08T...")
}
$project
{_id:"303900",
ips:[
{ip:"71.56.112.56",
ts:ISODate("2017-05-08T...")
},
{ip:"71.56.112.56",
ts:ISODate("2017-05-09T...")
},
{ip:"12.130.117.87",
ts:ISODate("2017-05-09T...")
}
]}
{$match:{ts:{$gte:start,$lt:end}}},
{$sort:{ts:1}},
{$group:{_id:"$user",ips:{$push:{ip:"$ipaddr", ts:"$ts"}}}},
{$addFields:{diffs: {$filter:{
input:{$map:{
input: {$range:[0,{$subtract:[{$size:"$ips"},1]}]}, as:"i",
in:{$let:{vars:{ip1:{$arrayElemAt:["$ips","$$i"]},
ip2:{$arrayElemAt:["$ips",{$add:["$$i",1]}]}},
in:{
diff:{$divide:[{$subtract:["$$ip2.ts","$$ip1.ts"]},60000]},
ip1:"$$ip1.ip", t1:"$$ip1.ts",
ip2:"$$ip2.ip", t2:"$$ip2.ts"
}}}}},
cond:{$and:[{$lt:["$$this.diff",10]},{$ne:["$$this.ip1","$$this.ip2"]}]}
}}}},
$sort$match $group $addFields $match
start=ISODate("...")
end=ISODate("...")
{
user: "303900",
ipaddr: "71.56.112.56",
ts:ISODate("2017-05-08T...")
}
$project
{_id:"303900",
ips:[
{ip:"71.56.112.56",
ts:ISODate("2017-05-08T...")
},
{ip:"71.56.112.56",
ts:ISODate("2017-05-09T...")
},
{ip:"12.130.117.87",
ts:ISODate("2017-05-09T...")
}
]}
{$match:{ts:{$gte:start,$lt:end}}},
{$sort:{ts:1}},
{$group:{_id:"$user",ips:{$push:{ip:"$ipaddr", ts:"$ts"}}}},
{$addFields:{diffs: {$filter:{
input:{$map:{
input: {$range:[0,{$subtract:[{$size:"$ips"},1]}]}, as:"i",
in:{$let:{vars:{ip1:{$arrayElemAt:["$ips","$$i"]},
ip2:{$arrayElemAt:["$ips",{$add:["$$i",1]}]}},
in:{
diff:{$divide:[{$subtract:["$$ip2.ts","$$ip1.ts"]},60000]},
ip1:"$$ip1.ip", t1:"$$ip1.ts",
ip2:"$$ip2.ip", t2:"$$ip2.ts"
}}}}},
cond:{$and:[{$lt:["$$this.diff",10]},{$ne:["$$this.ip1","$$this.ip2"]}]}
}}}},
{$match:{"diffs":{$ne:[]}}},
{$project:{_id:0, user:"$_id", suspectLogins:"$diffs"}}
$sort$match $group $addFields $match
start=ISODate("...")
end=ISODate("...")
{
user: "303900",
ipaddr: "71.56.112.56",
ts:ISODate("2017-05-08T...")
}
$project
{$match:{ts:{$gte:start,$lt:end}}},
{$sort:{ts:1}},
{$group:{_id:"$user",ips:{$push:{ip:"$ipaddr", ts:"$ts"}}}},
{$addFields:{diffs: {$filter:{
input:{$map:{
input: {$range:[0,{$subtract:[{$size:"$ips"},1]}]}, as:"i",
in:{$let:{vars:{ip1:{$arrayElemAt:["$ips","$$i"]},
ip2:{$arrayElemAt:["$ips",{$add:["$$i",1]}]}},
in:{
diff:{$divide:[{$subtract:["$$ip2.ts","$$ip1.ts"]},60000]},
ip1:"$$ip1.ip", t1:"$$ip1.ts",
ip2:"$$ip2.ip", t2:"$$ip2.ts"
}}}}},
cond:{$and:[{$lt:["$$this.diff",10]},{$ne:["$$this.ip1","$$this.ip2"]}]}
}}}},
{$match:{"diffs":{$ne:[]}}},
{$project:{_id:0, user:"$_id", suspectLogins:"$diffs"}}
{"user":"35237073",
"suspectLogins":[
{"diff":4.8333333333,
"ip1":"106.220.151.16",
"t1":"2017-05-08T06:58",
"ip2":"223.182.113.15"
"t2":"2017-05-08T07:03"
},
{"diff":8.3,
"ip1":"223.182.113.15",
"t1":"2017-05-08T07:03",
"ip2":"49.206.217.26",
"t2":"2017-05-08T07:11"
}
]
}
$sort$match $group $addFields $match $project
{$match:{ts:{$gte:start,$lt:end}}},
{$sort:{ts:1}},
{$group:{_id:"$user",ips:{$push:{ip:"$ipaddr", ts:"$ts"}}}},
{$addFields:{diffs: {$filter:{
input:{$map:{
input: {$range:[0,{$subtract:[{$size:"$ips"},1]}]}, as:"i",
in:{$let:{vars:{ip1:{$arrayElemAt:["$ips","$$i"]},
ip2:{$arrayElemAt:["$ips",{$add:["$$i",1]}]}},
in:{
diff:{$divide:[{$subtract:["$$ip2.ts","$$ip1.ts"]},60000]},
ip1:"$$ip1.ip", t1:"$$ip1.ts",
ip2:"$$ip2.ip", t2:"$$ip2.ts"
}}}}},
cond:{$and:[{$lt:["$$this.diff",10]},{$ne:["$$this.ip1","$$this.ip2"]}]}
}}}},
{$match:{"diffs":{$ne:[]}}},
{$project:{_id:0, user:"$_id", suspectLogins:"$diffs"}}
start=ISODate("...")
end=ISODate("...")
{
user: "303900",
ipaddr: "71.56.112.56",
ts:ISODate("2017-05-08T...")
}
{"user":"35237073",
"suspectLogins":[
{"diff":4.8333333333,
"ip1":"106.220.151.16",
"t1":"2017-05-08T06:58",
"ip2":"223.182.113.15"
"t2":"2017-05-08T07:03"
},
{"diff":8.3,
"ip1":"223.182.113.15",
"t1":"2017-05-08T07:03",
"ip2":"49.206.217.26",
"t2":"2017-05-08T07:11"
}
]
}
$sort$match $group $addFields $match
start=ISODate("...")
end=ISODate("...")
{
user: "303900",
ipaddr: "71.56.112.56",
ts:ISODate("2017-05-08T...")
}
$addFields $match $proj
{$match:{ts:{$gte:start,$lt:end}}},
{$sort:{ts:1}},
{$group:{_id:"$user",ips:{$push:{ip:"$ipaddr", ts:"$ts"}}}},
{$addFields:{diffIpNum:{$size:{$setUnion:"$ips.ip"}}}},
{$match:{diffIpNum:{$gt:1}}},
{$addFields:{diffs: {$filter:{
input:{$map:{
input: {$range:[0,{$subtract:[{$size:"$ips"},1]}]}, as:"i",
in:{$let:{vars:{ip1:{$arrayElemAt:["$ips","$$i"]},
ip2:{$arrayElemAt:["$ips",{$add:["$$i",1]}]}},
in:{
diff:{$divide:[{$subtract:["$$ip2.ts","$$ip1.ts"]},60000]},
ip1:"$$ip1.ip", t1:"$$ip1.ts",
ip2:"$$ip2.ip", t2:"$$ip2.ts"
}}}}},
cond:{$and:[{$lt:["$$this.diff",10]},{$ne:["$$this.ip1","$$this.ip2"]}]}
}}}},
{$match:{"diffs":{$ne:[]}}},
{$project:{_id:0, user:"$_id", suspectLogins:"$diffs"}}
{"user":"35237073",
"suspectLogins":[
{"diff":4.8333333333,
"ip1":"106.220.151.16",
"t1":"2017-05-08T06:58",
"ip2":"223.182.113.15"
"t2":"2017-05-08T07:03"
},
{"diff":8.3,
"ip1":"223.182.113.15",
"t1":"2017-05-08T07:03",
"ip2":"49.206.217.26",
"t2":"2017-05-08T07:11"
}
]
}
$sort$match $group $match
start=ISODate("...")
end=ISODate("...")
{
user: "303900",
ipaddr: "71.56.112.56",
ts:ISODate("2017-05-08T...")
}
$addFields $match $project
{$match:{ts:{$gte:start,$lt:end}}},
{$sort:{ts:1}},
{$group:{_id:"$user",ips:{$push:{ip:"$ipaddr", ts:"$ts"}},
diffIps:{$addToSet:"$ipaddr"}}},
{$match:{"diffIps.1":{$exists:true}}},
{$addFields:{diffs: {$filter:{
input:{$map:{
input: {$range:[0,{$subtract:[{$size:"$ips"},1]}]}, as:"i",
in:{$let:{vars:{ip1:{$arrayElemAt:["$ips","$$i"]},
ip2:{$arrayElemAt:["$ips",{$add:["$$i",1]}]}},
in:{
diff:{$divide:[{$subtract:["$$ip2.ts","$$ip1.ts"]},60000]},
ip1:"$$ip1.ip", t1:"$$ip1.ts",
ip2:"$$ip2.ip", t2:"$$ip2.ts"
}}}}},
cond:{$and:[{$lt:["$$this.diff",10]},{$ne:["$$this.ip1","$$this.ip2"]}]}
}}}},
{$match:{"diffs":{$ne:[]}}},
{$project:{_id:0, user:"$_id", suspectLogins:"$diffs"}}
{"user":"35237073",
"suspectLogins":[
{"diff":4.8333333333,
"ip1":"106.220.151.16",
"t1":"2017-05-08T06:58",
"ip2":"223.182.113.15"
"t2":"2017-05-08T07:03"
},
{"diff":8.3,
"ip1":"223.182.113.15",
"t1":"2017-05-08T07:03",
"ip2":"49.206.217.26",
"t2":"2017-05-08T07:11"
}
]
}
$sort$match $group
start=ISODate("...")
end=ISODate("...")
{
user: "303900",
ipaddr: "71.56.112.56",
ts:ISODate("2017-05-08T...")
}
{$match:{ts:{$gte:start,$lt:end}}},
{$sort:{ts:1}},
{$group:{_id:"$user",ips:{$push:{ip:"$ipaddr", ts:"$ts"}},
diffIps:{$addToSet:"$ipaddr"}}},
{$match:{"diffIps.1":{$exists:true}}},
{$addFields:{diffs: {$filter:{
input:{$map:{
input: {$range:[0,{$subtract:[{$size:"$ips"},1]}]}, as:"i",
in:{$let:{vars:{ip1:{$arrayElemAt:["$ips","$$i"]},
ip2:{$arrayElemAt:["$ips",{$add:["$$i",1]}]}},
in:{
diff:{$divide:[{$subtract:["$$ip2.ts","$$ip1.ts"]},60000]},
ip1:"$$ip1.ip", t1:"$$ip1.ts",
ip2:"$$ip2.ip", t2:"$$ip2.ts"
}}}}},
cond:{$and:[{$lt:["$$this.diff",10]},{$ne:["$$this.ip1","$$this.ip2"]}]}
}}}},
{$match:{"diffs":{$ne:[]}}},
{$project:{_id:0, user:"$_id", suspectLogins:"$diffs"}}
{"user":"35237073",
"suspectLogins":[
{"diff":4.8333333333,
"ip1":"106.220.151.16",
"t1":"2017-05-08T06:58",
"ip2":"223.182.113.15"
"t2":"2017-05-08T07:03"
},
{"diff":8.3,
"ip1":"223.182.113.15",
"t1":"2017-05-08T07:03",
"ip2":"49.206.217.26",
"t2":"2017-05-08T07:11"
}
]
} $match $addFields $match $project
$sort$match $group
start=ISODate("...")
end=ISODate("...")
{
user: "303900",
ipaddr: "71.56.112.56",
ts:ISODate("2017-05-08T...")
}
{$match:{ts:{$gte:start,$lt:end}}},
{$sort:{ts:1}},
{$group:{_id:"$user",ips:{$push:{ip:"$ipaddr", ts:"$ts"}},
diffIps:{$addToSet:"$ipaddr"}}},
{$match:{"diffIps.1":{$exists:true}}},
{$addFields:{diffs: {$filter:{
input:{$map:{
input: {$range:[0,{$subtract:[{$size:"$ips"},1]}]}, as:"i",
in:{$let:{vars:{ip1:{$arrayElemAt:["$ips","$$i"]},
ip2:{$arrayElemAt:["$ips",{$add:["$$i",1]}]}},
in:{
diff:{$cond:{
}},
ip1:"$$ip1.ip", t1:"$$ip1.ts",
ip2:"$$ip2.ip", t2:"$$ip2.ts"
}}}}},
cond:{$and:[{$lt:["$$this.diff",10]},{$ne:["$$this.ip1","$$this.ip2"]}]}
}}}},
{$match:{"diffs":{$ne:[]}}},
{$project:{_id:0, user:"$_id", suspectLogins:"$diffs"}}
{"user":"35237073",
"suspectLogins":[
{"diff":4.8333333333,
"ip1":"106.220.151.16",
"t1":"2017-05-08T06:58",
"ip2":"223.182.113.15"
"t2":"2017-05-08T07:03"
},
{"diff":8.3,
"ip1":"223.182.113.15",
"t1":"2017-05-08T07:03",
"ip2":"49.206.217.26",
"t2":"2017-05-08T07:11"
}
]
} $match $addFields $match $project
$sort$match $group
start=ISODate("...")
end=ISODate("...")
{
user: "303900",
ipaddr: "71.56.112.56",
ts:ISODate("2017-05-08T...")
}
{$match:{ts:{$gte:start,$lt:end}}},
{$sort:{ts:1}},
{$group:{_id:"$user",ips:{$push:{ip:"$ipaddr", ts:"$ts"}},
diffIps:{$addToSet:"$ipaddr"}}},
{$match:{"diffIps.1":{$exists:true}}},
{$addFields:{diffs: {$filter:{
input:{$map:{
input: {$range:[0,{$subtract:[{$size:"$ips"},1]}]}, as:"i",
in:{$let:{vars:{ip1:{$arrayElemAt:["$ips","$$i"]},
ip2:{$arrayElemAt:["$ips",{$add:["$$i",1]}]}},
in:{
diff:{$cond:{
if:{$ne:["$$this.ip1","$$this.ip2"]},
then:{$divide:[{$subtract:["$$ip2.ts","$$ip1.ts"]},60000]}]},
else: 9999 }},
ip1:"$$ip1.ip", t1:"$$ip1.ts",
ip2:"$$ip2.ip", t2:"$$ip2.ts"
}}}}},
cond:{$and:[{$lt:["$$this.diff",10]},{$ne:["$$this.ip1","$$this.ip2"]}]}
}}}},
{$match:{"diffs":{$ne:[]}}},
{$project:{_id:0, user:"$_id", suspectLogins:"$diffs"}}
{"user":"35237073",
"suspectLogins":[
{"diff":4.8333333333,
"ip1":"106.220.151.16",
"t1":"2017-05-08T06:58",
"ip2":"223.182.113.15"
"t2":"2017-05-08T07:03"
},
{"diff":8.3,
"ip1":"223.182.113.15",
"t1":"2017-05-08T07:03",
"ip2":"49.206.217.26",
"t2":"2017-05-08T07:11"
}
]
} $match $addFields $match $project
$sort$match $group
start=ISODate("...")
end=ISODate("...")
{
user: "303900",
ipaddr: "71.56.112.56",
ts:ISODate("2017-05-08T...")
}
{$match:{ts:{$gte:start,$lt:end}}},
{$sort:{ts:1}},
{$group:{_id:"$user",ips:{$push:{ip:"$ipaddr", ts:"$ts"}},
diffIps:{$addToSet:"$ipaddr"}}},
{$match:{"diffIps.1":{$exists:true}}},
{$addFields:{diffs: {$filter:{
input:{$map:{
input: {$range:[0,{$subtract:[{$size:"$ips"},1]}]}, as:"i",
in:{$let:{vars:{ip1:{$arrayElemAt:["$ips","$$i"]},
ip2:{$arrayElemAt:["$ips",{$add:["$$i",1]}]}},
in:{
diff:{$cond:{
if:{$ne:["$$this.ip1","$$this.ip2"]},
then:{$divide:[{$subtract:["$$ip2.ts","$$ip1.ts"]},60000]}]},
else: 9999 }},
ip1:"$$ip1.ip", t1:"$$ip1.ts",
ip2:"$$ip2.ip", t2:"$$ip2.ts"
}}}}},
cond:{$and:[{$lt:["$$this.diff",10]},{$ne:["$$this.ip1","$$this.ip2"]}]}
}}}},
{$match:{"diffs":{$ne:[]}}},
{$project:{_id:0, user:"$_id", suspectLogins:"$diffs"}}
{"user":"35237073",
"suspectLogins":[
{"diff":4.8333333333,
"ip1":"106.220.151.16",
"t1":"2017-05-08T06:58",
"ip2":"223.182.113.15"
"t2":"2017-05-08T07:03"
},
{"diff":8.3,
"ip1":"223.182.113.15",
"t1":"2017-05-08T07:03",
"ip2":"49.206.217.26",
"t2":"2017-05-08T07:11"
}
]
} $match $addFields $match $project
$sort$match $group
start=ISODate("...")
end=ISODate("...")
{
user: "303900",
ipaddr: "71.56.112.56",
ts:ISODate("2017-05-08T...")
}
{$match:{ts:{$gte:start,$lt:end}}},
{$sort:{ts:1}},
{$group:{_id:"$user",ips:{$push:{ip:"$ipaddr", ts:"$ts"}},
diffIps:{$addToSet:"$ipaddr"}}},
{$match:{"diffIps.1":{$exists:true}}},
{$addFields:{diffs: {$filter:{
input:{$map:{
input: {$range:[0,{$subtract:[{$size:"$ips"},1]}]}, as:"i",
in:{$let:{vars:{ip1:{$arrayElemAt:["$ips","$$i"]},
ip2:{$arrayElemAt:["$ips",{$add:["$$i",1]}]}},
in:{
diff:{$cond:{
if:{$ne:["$$this.ip1","$$this.ip2"]},
then:{$divide:[{$subtract:["$$ip2.ts","$$ip1.ts"]},60000]}]},
else: 9999 }},
ip1:"$$ip1.ip", t1:"$$ip1.ts",
ip2:"$$ip2.ip", t2:"$$ip2.ts"
}}}}},
cond:{$lt:["$$this.diff",10]}
}}}},
{$match:{"diffs":{$ne:[]}}},
{$project:{_id:0, user:"$_id", suspectLogins:"$diffs"}}
{"user":"35237073",
"suspectLogins":[
{"diff":4.8333333333,
"ip1":"106.220.151.16",
"t1":"2017-05-08T06:58",
"ip2":"223.182.113.15"
"t2":"2017-05-08T07:03"
},
{"diff":8.3,
"ip1":"223.182.113.15",
"t1":"2017-05-08T07:03",
"ip2":"49.206.217.26",
"t2":"2017-05-08T07:11"
}
]
} $match $addFields $match $project
#MDBTOUR
POWERFUL AGGREGATIONS
understand stages
• Best order for performance
• Avoid unnecessary "blocking"
• keep "streaming"
• Maximize use of indexes
• early stages get the index!
• Liberally check explain() output
understand expressions
• Schema manipulation
• Array transformation
use functions
• Readable, debug-able, reusable
#MDBTOUR
THE FUTURE OF AGGREGATION
Better performance & optimizations
More stages & expressions
More options for output
Compass helper for aggregate
https://github.com/asya999/mdbw17
https://github.com/asya999/mdbw17
# M D B l o c a l
THANK YOU!
https://github.com/asya999/mdbw17
Powerful Analysis with the Aggregation Pipeline

More Related Content

What's hot

Data Governance with JSON Schema
Data Governance with JSON SchemaData Governance with JSON Schema
Data Governance with JSON SchemaMongoDB
 
Webinar: Strongly Typed Languages and Flexible Schemas
Webinar: Strongly Typed Languages and Flexible SchemasWebinar: Strongly Typed Languages and Flexible Schemas
Webinar: Strongly Typed Languages and Flexible SchemasMongoDB
 
Strongly Typed Languages and Flexible Schemas
Strongly Typed Languages and Flexible SchemasStrongly Typed Languages and Flexible Schemas
Strongly Typed Languages and Flexible SchemasNorberto Leite
 
MongoDB Europe 2016 - Debugging MongoDB Performance
MongoDB Europe 2016 - Debugging MongoDB PerformanceMongoDB Europe 2016 - Debugging MongoDB Performance
MongoDB Europe 2016 - Debugging MongoDB PerformanceMongoDB
 
Webinar: Exploring the Aggregation Framework
Webinar: Exploring the Aggregation FrameworkWebinar: Exploring the Aggregation Framework
Webinar: Exploring the Aggregation FrameworkMongoDB
 
MongoDB World 2019: Aggregation Pipeline Power++: How MongoDB 4.2 Pipeline Em...
MongoDB World 2019: Aggregation Pipeline Power++: How MongoDB 4.2 Pipeline Em...MongoDB World 2019: Aggregation Pipeline Power++: How MongoDB 4.2 Pipeline Em...
MongoDB World 2019: Aggregation Pipeline Power++: How MongoDB 4.2 Pipeline Em...MongoDB
 
MongoDB .local Chicago 2019: Aggregation Pipeline Power++: How MongoDB 4.2 Pi...
MongoDB .local Chicago 2019: Aggregation Pipeline Power++: How MongoDB 4.2 Pi...MongoDB .local Chicago 2019: Aggregation Pipeline Power++: How MongoDB 4.2 Pi...
MongoDB .local Chicago 2019: Aggregation Pipeline Power++: How MongoDB 4.2 Pi...MongoDB
 
MongoDB .local Toronto 2019: Aggregation Pipeline Power++: How MongoDB 4.2 Pi...
MongoDB .local Toronto 2019: Aggregation Pipeline Power++: How MongoDB 4.2 Pi...MongoDB .local Toronto 2019: Aggregation Pipeline Power++: How MongoDB 4.2 Pi...
MongoDB .local Toronto 2019: Aggregation Pipeline Power++: How MongoDB 4.2 Pi...MongoDB
 
MongoDB .local San Francisco 2020: Aggregation Pipeline Power++
MongoDB .local San Francisco 2020: Aggregation Pipeline Power++MongoDB .local San Francisco 2020: Aggregation Pipeline Power++
MongoDB .local San Francisco 2020: Aggregation Pipeline Power++MongoDB
 
Embedding a language into string interpolator
Embedding a language into string interpolatorEmbedding a language into string interpolator
Embedding a language into string interpolatorMichael Limansky
 
MongoDB Aggregation Framework
MongoDB Aggregation FrameworkMongoDB Aggregation Framework
MongoDB Aggregation FrameworkCaserta
 
MongoDB .local Bengaluru 2019: Aggregation Pipeline Power++: How MongoDB 4.2 ...
MongoDB .local Bengaluru 2019: Aggregation Pipeline Power++: How MongoDB 4.2 ...MongoDB .local Bengaluru 2019: Aggregation Pipeline Power++: How MongoDB 4.2 ...
MongoDB .local Bengaluru 2019: Aggregation Pipeline Power++: How MongoDB 4.2 ...MongoDB
 
Aggregation in MongoDB
Aggregation in MongoDBAggregation in MongoDB
Aggregation in MongoDBKishor Parkhe
 
Aggregation Framework
Aggregation FrameworkAggregation Framework
Aggregation FrameworkMongoDB
 
MongoDB Aggregation Framework
MongoDB Aggregation FrameworkMongoDB Aggregation Framework
MongoDB Aggregation FrameworkTyler Brock
 
The Aggregation Framework
The Aggregation FrameworkThe Aggregation Framework
The Aggregation FrameworkMongoDB
 
NoSQL を Ruby で実践するための n 個の方法
NoSQL を Ruby で実践するための n 個の方法NoSQL を Ruby で実践するための n 個の方法
NoSQL を Ruby で実践するための n 個の方法Tomohiro Nishimura
 
Coding Horrors
Coding HorrorsCoding Horrors
Coding HorrorsMark Baker
 

What's hot (20)

Data Governance with JSON Schema
Data Governance with JSON SchemaData Governance with JSON Schema
Data Governance with JSON Schema
 
Webinar: Strongly Typed Languages and Flexible Schemas
Webinar: Strongly Typed Languages and Flexible SchemasWebinar: Strongly Typed Languages and Flexible Schemas
Webinar: Strongly Typed Languages and Flexible Schemas
 
Strongly Typed Languages and Flexible Schemas
Strongly Typed Languages and Flexible SchemasStrongly Typed Languages and Flexible Schemas
Strongly Typed Languages and Flexible Schemas
 
MongoDB Europe 2016 - Debugging MongoDB Performance
MongoDB Europe 2016 - Debugging MongoDB PerformanceMongoDB Europe 2016 - Debugging MongoDB Performance
MongoDB Europe 2016 - Debugging MongoDB Performance
 
Webinar: Exploring the Aggregation Framework
Webinar: Exploring the Aggregation FrameworkWebinar: Exploring the Aggregation Framework
Webinar: Exploring the Aggregation Framework
 
MongoDB World 2019: Aggregation Pipeline Power++: How MongoDB 4.2 Pipeline Em...
MongoDB World 2019: Aggregation Pipeline Power++: How MongoDB 4.2 Pipeline Em...MongoDB World 2019: Aggregation Pipeline Power++: How MongoDB 4.2 Pipeline Em...
MongoDB World 2019: Aggregation Pipeline Power++: How MongoDB 4.2 Pipeline Em...
 
MongoDB (Advanced)
MongoDB (Advanced)MongoDB (Advanced)
MongoDB (Advanced)
 
MongoDB .local Chicago 2019: Aggregation Pipeline Power++: How MongoDB 4.2 Pi...
MongoDB .local Chicago 2019: Aggregation Pipeline Power++: How MongoDB 4.2 Pi...MongoDB .local Chicago 2019: Aggregation Pipeline Power++: How MongoDB 4.2 Pi...
MongoDB .local Chicago 2019: Aggregation Pipeline Power++: How MongoDB 4.2 Pi...
 
MongoDB .local Toronto 2019: Aggregation Pipeline Power++: How MongoDB 4.2 Pi...
MongoDB .local Toronto 2019: Aggregation Pipeline Power++: How MongoDB 4.2 Pi...MongoDB .local Toronto 2019: Aggregation Pipeline Power++: How MongoDB 4.2 Pi...
MongoDB .local Toronto 2019: Aggregation Pipeline Power++: How MongoDB 4.2 Pi...
 
MongoDB .local San Francisco 2020: Aggregation Pipeline Power++
MongoDB .local San Francisco 2020: Aggregation Pipeline Power++MongoDB .local San Francisco 2020: Aggregation Pipeline Power++
MongoDB .local San Francisco 2020: Aggregation Pipeline Power++
 
Embedding a language into string interpolator
Embedding a language into string interpolatorEmbedding a language into string interpolator
Embedding a language into string interpolator
 
MongoDB Aggregation Framework
MongoDB Aggregation FrameworkMongoDB Aggregation Framework
MongoDB Aggregation Framework
 
MongoDB .local Bengaluru 2019: Aggregation Pipeline Power++: How MongoDB 4.2 ...
MongoDB .local Bengaluru 2019: Aggregation Pipeline Power++: How MongoDB 4.2 ...MongoDB .local Bengaluru 2019: Aggregation Pipeline Power++: How MongoDB 4.2 ...
MongoDB .local Bengaluru 2019: Aggregation Pipeline Power++: How MongoDB 4.2 ...
 
Aggregation in MongoDB
Aggregation in MongoDBAggregation in MongoDB
Aggregation in MongoDB
 
Aggregation Framework
Aggregation FrameworkAggregation Framework
Aggregation Framework
 
MongoDB Aggregation Framework
MongoDB Aggregation FrameworkMongoDB Aggregation Framework
MongoDB Aggregation Framework
 
The Aggregation Framework
The Aggregation FrameworkThe Aggregation Framework
The Aggregation Framework
 
NoSQL を Ruby で実践するための n 個の方法
NoSQL を Ruby で実践するための n 個の方法NoSQL を Ruby で実践するための n 個の方法
NoSQL を Ruby で実践するための n 個の方法
 
Indexing
IndexingIndexing
Indexing
 
Coding Horrors
Coding HorrorsCoding Horrors
Coding Horrors
 

Similar to Powerful Analysis with the Aggregation Pipeline

[MongoDB.local Bengaluru 2018] Tutorial: Pipeline Power - Doing More with Mon...
[MongoDB.local Bengaluru 2018] Tutorial: Pipeline Power - Doing More with Mon...[MongoDB.local Bengaluru 2018] Tutorial: Pipeline Power - Doing More with Mon...
[MongoDB.local Bengaluru 2018] Tutorial: Pipeline Power - Doing More with Mon...MongoDB
 
MongoDB .local Munich 2019: Aggregation Pipeline Power++: How MongoDB 4.2 Pip...
MongoDB .local Munich 2019: Aggregation Pipeline Power++: How MongoDB 4.2 Pip...MongoDB .local Munich 2019: Aggregation Pipeline Power++: How MongoDB 4.2 Pip...
MongoDB .local Munich 2019: Aggregation Pipeline Power++: How MongoDB 4.2 Pip...MongoDB
 
The Aggregation Framework
The Aggregation FrameworkThe Aggregation Framework
The Aggregation FrameworkMongoDB
 
Max Neunhöffer – Joins and aggregations in a distributed NoSQL DB - NoSQL mat...
Max Neunhöffer – Joins and aggregations in a distributed NoSQL DB - NoSQL mat...Max Neunhöffer – Joins and aggregations in a distributed NoSQL DB - NoSQL mat...
Max Neunhöffer – Joins and aggregations in a distributed NoSQL DB - NoSQL mat...NoSQLmatters
 
Webinar: Data Processing and Aggregation Options
Webinar: Data Processing and Aggregation OptionsWebinar: Data Processing and Aggregation Options
Webinar: Data Processing and Aggregation OptionsMongoDB
 
MongoDB .local Paris 2020: La puissance du Pipeline d'Agrégation de MongoDB
MongoDB .local Paris 2020: La puissance du Pipeline d'Agrégation de MongoDBMongoDB .local Paris 2020: La puissance du Pipeline d'Agrégation de MongoDB
MongoDB .local Paris 2020: La puissance du Pipeline d'Agrégation de MongoDBMongoDB
 
MongoDB Aggregations Indexing and Profiling
MongoDB Aggregations Indexing and ProfilingMongoDB Aggregations Indexing and Profiling
MongoDB Aggregations Indexing and ProfilingManish Kapoor
 
Introduction to MongoDB for C# developers
Introduction to MongoDB for C# developersIntroduction to MongoDB for C# developers
Introduction to MongoDB for C# developersTaras Romanyk
 
Query for json databases
Query for json databasesQuery for json databases
Query for json databasesBinh Le
 
Agg framework selectgroup feb2015 v2
Agg framework selectgroup feb2015 v2Agg framework selectgroup feb2015 v2
Agg framework selectgroup feb2015 v2MongoDB
 
Couchbase presentation - by Patrick Heneise
Couchbase presentation - by Patrick HeneiseCouchbase presentation - by Patrick Heneise
Couchbase presentation - by Patrick Heneiseitnig
 
Webinar: Applikationsentwicklung mit MongoDB : Teil 5: Reporting & Aggregation
Webinar: Applikationsentwicklung mit MongoDB: Teil 5: Reporting & AggregationWebinar: Applikationsentwicklung mit MongoDB: Teil 5: Reporting & Aggregation
Webinar: Applikationsentwicklung mit MongoDB : Teil 5: Reporting & AggregationMongoDB
 
Joins and Other MongoDB 3.2 Aggregation Enhancements
Joins and Other MongoDB 3.2 Aggregation EnhancementsJoins and Other MongoDB 3.2 Aggregation Enhancements
Joins and Other MongoDB 3.2 Aggregation EnhancementsAndrew Morgan
 
MongoDB.local DC 2018: Tutorial - Data Analytics with MongoDB
MongoDB.local DC 2018: Tutorial - Data Analytics with MongoDBMongoDB.local DC 2018: Tutorial - Data Analytics with MongoDB
MongoDB.local DC 2018: Tutorial - Data Analytics with MongoDBMongoDB
 
De normalised london aggregation framework overview
De normalised london  aggregation framework overview De normalised london  aggregation framework overview
De normalised london aggregation framework overview Chris Harris
 
MongoDB Aggregation Framework in action !
MongoDB Aggregation Framework in action !MongoDB Aggregation Framework in action !
MongoDB Aggregation Framework in action !Sébastien Prunier
 
Modern Application Foundations: Underscore and Twitter Bootstrap
Modern Application Foundations: Underscore and Twitter BootstrapModern Application Foundations: Underscore and Twitter Bootstrap
Modern Application Foundations: Underscore and Twitter BootstrapHoward Lewis Ship
 
1403 app dev series - session 5 - analytics
1403   app dev series - session 5 - analytics1403   app dev series - session 5 - analytics
1403 app dev series - session 5 - analyticsMongoDB
 

Similar to Powerful Analysis with the Aggregation Pipeline (20)

[MongoDB.local Bengaluru 2018] Tutorial: Pipeline Power - Doing More with Mon...
[MongoDB.local Bengaluru 2018] Tutorial: Pipeline Power - Doing More with Mon...[MongoDB.local Bengaluru 2018] Tutorial: Pipeline Power - Doing More with Mon...
[MongoDB.local Bengaluru 2018] Tutorial: Pipeline Power - Doing More with Mon...
 
MongoDB .local Munich 2019: Aggregation Pipeline Power++: How MongoDB 4.2 Pip...
MongoDB .local Munich 2019: Aggregation Pipeline Power++: How MongoDB 4.2 Pip...MongoDB .local Munich 2019: Aggregation Pipeline Power++: How MongoDB 4.2 Pip...
MongoDB .local Munich 2019: Aggregation Pipeline Power++: How MongoDB 4.2 Pip...
 
The Aggregation Framework
The Aggregation FrameworkThe Aggregation Framework
The Aggregation Framework
 
Max Neunhöffer – Joins and aggregations in a distributed NoSQL DB - NoSQL mat...
Max Neunhöffer – Joins and aggregations in a distributed NoSQL DB - NoSQL mat...Max Neunhöffer – Joins and aggregations in a distributed NoSQL DB - NoSQL mat...
Max Neunhöffer – Joins and aggregations in a distributed NoSQL DB - NoSQL mat...
 
Webinar: Data Processing and Aggregation Options
Webinar: Data Processing and Aggregation OptionsWebinar: Data Processing and Aggregation Options
Webinar: Data Processing and Aggregation Options
 
MongoDB .local Paris 2020: La puissance du Pipeline d'Agrégation de MongoDB
MongoDB .local Paris 2020: La puissance du Pipeline d'Agrégation de MongoDBMongoDB .local Paris 2020: La puissance du Pipeline d'Agrégation de MongoDB
MongoDB .local Paris 2020: La puissance du Pipeline d'Agrégation de MongoDB
 
Querying mongo db
Querying mongo dbQuerying mongo db
Querying mongo db
 
MongoDB Aggregations Indexing and Profiling
MongoDB Aggregations Indexing and ProfilingMongoDB Aggregations Indexing and Profiling
MongoDB Aggregations Indexing and Profiling
 
Introduction to MongoDB for C# developers
Introduction to MongoDB for C# developersIntroduction to MongoDB for C# developers
Introduction to MongoDB for C# developers
 
MongoDB 3.2 - Analytics
MongoDB 3.2  - AnalyticsMongoDB 3.2  - Analytics
MongoDB 3.2 - Analytics
 
Query for json databases
Query for json databasesQuery for json databases
Query for json databases
 
Agg framework selectgroup feb2015 v2
Agg framework selectgroup feb2015 v2Agg framework selectgroup feb2015 v2
Agg framework selectgroup feb2015 v2
 
Couchbase presentation - by Patrick Heneise
Couchbase presentation - by Patrick HeneiseCouchbase presentation - by Patrick Heneise
Couchbase presentation - by Patrick Heneise
 
Webinar: Applikationsentwicklung mit MongoDB : Teil 5: Reporting & Aggregation
Webinar: Applikationsentwicklung mit MongoDB: Teil 5: Reporting & AggregationWebinar: Applikationsentwicklung mit MongoDB: Teil 5: Reporting & Aggregation
Webinar: Applikationsentwicklung mit MongoDB : Teil 5: Reporting & Aggregation
 
Joins and Other MongoDB 3.2 Aggregation Enhancements
Joins and Other MongoDB 3.2 Aggregation EnhancementsJoins and Other MongoDB 3.2 Aggregation Enhancements
Joins and Other MongoDB 3.2 Aggregation Enhancements
 
MongoDB.local DC 2018: Tutorial - Data Analytics with MongoDB
MongoDB.local DC 2018: Tutorial - Data Analytics with MongoDBMongoDB.local DC 2018: Tutorial - Data Analytics with MongoDB
MongoDB.local DC 2018: Tutorial - Data Analytics with MongoDB
 
De normalised london aggregation framework overview
De normalised london  aggregation framework overview De normalised london  aggregation framework overview
De normalised london aggregation framework overview
 
MongoDB Aggregation Framework in action !
MongoDB Aggregation Framework in action !MongoDB Aggregation Framework in action !
MongoDB Aggregation Framework in action !
 
Modern Application Foundations: Underscore and Twitter Bootstrap
Modern Application Foundations: Underscore and Twitter BootstrapModern Application Foundations: Underscore and Twitter Bootstrap
Modern Application Foundations: Underscore and Twitter Bootstrap
 
1403 app dev series - session 5 - analytics
1403   app dev series - session 5 - analytics1403   app dev series - session 5 - analytics
1403 app dev series - session 5 - analytics
 

More from MongoDB

MongoDB SoCal 2020: Migrate Anything* to MongoDB Atlas
MongoDB SoCal 2020: Migrate Anything* to MongoDB AtlasMongoDB SoCal 2020: Migrate Anything* to MongoDB Atlas
MongoDB SoCal 2020: Migrate Anything* to MongoDB AtlasMongoDB
 
MongoDB SoCal 2020: Go on a Data Safari with MongoDB Charts!
MongoDB SoCal 2020: Go on a Data Safari with MongoDB Charts!MongoDB SoCal 2020: Go on a Data Safari with MongoDB Charts!
MongoDB SoCal 2020: Go on a Data Safari with MongoDB Charts!MongoDB
 
MongoDB SoCal 2020: Using MongoDB Services in Kubernetes: Any Platform, Devel...
MongoDB SoCal 2020: Using MongoDB Services in Kubernetes: Any Platform, Devel...MongoDB SoCal 2020: Using MongoDB Services in Kubernetes: Any Platform, Devel...
MongoDB SoCal 2020: Using MongoDB Services in Kubernetes: Any Platform, Devel...MongoDB
 
MongoDB SoCal 2020: A Complete Methodology of Data Modeling for MongoDB
MongoDB SoCal 2020: A Complete Methodology of Data Modeling for MongoDBMongoDB SoCal 2020: A Complete Methodology of Data Modeling for MongoDB
MongoDB SoCal 2020: A Complete Methodology of Data Modeling for MongoDBMongoDB
 
MongoDB SoCal 2020: From Pharmacist to Analyst: Leveraging MongoDB for Real-T...
MongoDB SoCal 2020: From Pharmacist to Analyst: Leveraging MongoDB for Real-T...MongoDB SoCal 2020: From Pharmacist to Analyst: Leveraging MongoDB for Real-T...
MongoDB SoCal 2020: From Pharmacist to Analyst: Leveraging MongoDB for Real-T...MongoDB
 
MongoDB SoCal 2020: Best Practices for Working with IoT and Time-series Data
MongoDB SoCal 2020: Best Practices for Working with IoT and Time-series DataMongoDB SoCal 2020: Best Practices for Working with IoT and Time-series Data
MongoDB SoCal 2020: Best Practices for Working with IoT and Time-series DataMongoDB
 
MongoDB SoCal 2020: MongoDB Atlas Jump Start
 MongoDB SoCal 2020: MongoDB Atlas Jump Start MongoDB SoCal 2020: MongoDB Atlas Jump Start
MongoDB SoCal 2020: MongoDB Atlas Jump StartMongoDB
 
MongoDB .local San Francisco 2020: Powering the new age data demands [Infosys]
MongoDB .local San Francisco 2020: Powering the new age data demands [Infosys]MongoDB .local San Francisco 2020: Powering the new age data demands [Infosys]
MongoDB .local San Francisco 2020: Powering the new age data demands [Infosys]MongoDB
 
MongoDB .local San Francisco 2020: Using Client Side Encryption in MongoDB 4.2
MongoDB .local San Francisco 2020: Using Client Side Encryption in MongoDB 4.2MongoDB .local San Francisco 2020: Using Client Side Encryption in MongoDB 4.2
MongoDB .local San Francisco 2020: Using Client Side Encryption in MongoDB 4.2MongoDB
 
MongoDB .local San Francisco 2020: Using MongoDB Services in Kubernetes: any ...
MongoDB .local San Francisco 2020: Using MongoDB Services in Kubernetes: any ...MongoDB .local San Francisco 2020: Using MongoDB Services in Kubernetes: any ...
MongoDB .local San Francisco 2020: Using MongoDB Services in Kubernetes: any ...MongoDB
 
MongoDB .local San Francisco 2020: Go on a Data Safari with MongoDB Charts!
MongoDB .local San Francisco 2020: Go on a Data Safari with MongoDB Charts!MongoDB .local San Francisco 2020: Go on a Data Safari with MongoDB Charts!
MongoDB .local San Francisco 2020: Go on a Data Safari with MongoDB Charts!MongoDB
 
MongoDB .local San Francisco 2020: From SQL to NoSQL -- Changing Your Mindset
MongoDB .local San Francisco 2020: From SQL to NoSQL -- Changing Your MindsetMongoDB .local San Francisco 2020: From SQL to NoSQL -- Changing Your Mindset
MongoDB .local San Francisco 2020: From SQL to NoSQL -- Changing Your MindsetMongoDB
 
MongoDB .local San Francisco 2020: MongoDB Atlas Jumpstart
MongoDB .local San Francisco 2020: MongoDB Atlas JumpstartMongoDB .local San Francisco 2020: MongoDB Atlas Jumpstart
MongoDB .local San Francisco 2020: MongoDB Atlas JumpstartMongoDB
 
MongoDB .local San Francisco 2020: Tips and Tricks++ for Querying and Indexin...
MongoDB .local San Francisco 2020: Tips and Tricks++ for Querying and Indexin...MongoDB .local San Francisco 2020: Tips and Tricks++ for Querying and Indexin...
MongoDB .local San Francisco 2020: Tips and Tricks++ for Querying and Indexin...MongoDB
 
MongoDB .local San Francisco 2020: A Complete Methodology of Data Modeling fo...
MongoDB .local San Francisco 2020: A Complete Methodology of Data Modeling fo...MongoDB .local San Francisco 2020: A Complete Methodology of Data Modeling fo...
MongoDB .local San Francisco 2020: A Complete Methodology of Data Modeling fo...MongoDB
 
MongoDB .local San Francisco 2020: MongoDB Atlas Data Lake Technical Deep Dive
MongoDB .local San Francisco 2020: MongoDB Atlas Data Lake Technical Deep DiveMongoDB .local San Francisco 2020: MongoDB Atlas Data Lake Technical Deep Dive
MongoDB .local San Francisco 2020: MongoDB Atlas Data Lake Technical Deep DiveMongoDB
 
MongoDB .local San Francisco 2020: Developing Alexa Skills with MongoDB & Golang
MongoDB .local San Francisco 2020: Developing Alexa Skills with MongoDB & GolangMongoDB .local San Francisco 2020: Developing Alexa Skills with MongoDB & Golang
MongoDB .local San Francisco 2020: Developing Alexa Skills with MongoDB & GolangMongoDB
 
MongoDB .local Paris 2020: Realm : l'ingrédient secret pour de meilleures app...
MongoDB .local Paris 2020: Realm : l'ingrédient secret pour de meilleures app...MongoDB .local Paris 2020: Realm : l'ingrédient secret pour de meilleures app...
MongoDB .local Paris 2020: Realm : l'ingrédient secret pour de meilleures app...MongoDB
 
MongoDB .local Paris 2020: Upply @MongoDB : Upply : Quand le Machine Learning...
MongoDB .local Paris 2020: Upply @MongoDB : Upply : Quand le Machine Learning...MongoDB .local Paris 2020: Upply @MongoDB : Upply : Quand le Machine Learning...
MongoDB .local Paris 2020: Upply @MongoDB : Upply : Quand le Machine Learning...MongoDB
 
MongoDB .local Paris 2020: Les bonnes pratiques pour sécuriser MongoDB
MongoDB .local Paris 2020: Les bonnes pratiques pour sécuriser MongoDBMongoDB .local Paris 2020: Les bonnes pratiques pour sécuriser MongoDB
MongoDB .local Paris 2020: Les bonnes pratiques pour sécuriser MongoDBMongoDB
 

More from MongoDB (20)

MongoDB SoCal 2020: Migrate Anything* to MongoDB Atlas
MongoDB SoCal 2020: Migrate Anything* to MongoDB AtlasMongoDB SoCal 2020: Migrate Anything* to MongoDB Atlas
MongoDB SoCal 2020: Migrate Anything* to MongoDB Atlas
 
MongoDB SoCal 2020: Go on a Data Safari with MongoDB Charts!
MongoDB SoCal 2020: Go on a Data Safari with MongoDB Charts!MongoDB SoCal 2020: Go on a Data Safari with MongoDB Charts!
MongoDB SoCal 2020: Go on a Data Safari with MongoDB Charts!
 
MongoDB SoCal 2020: Using MongoDB Services in Kubernetes: Any Platform, Devel...
MongoDB SoCal 2020: Using MongoDB Services in Kubernetes: Any Platform, Devel...MongoDB SoCal 2020: Using MongoDB Services in Kubernetes: Any Platform, Devel...
MongoDB SoCal 2020: Using MongoDB Services in Kubernetes: Any Platform, Devel...
 
MongoDB SoCal 2020: A Complete Methodology of Data Modeling for MongoDB
MongoDB SoCal 2020: A Complete Methodology of Data Modeling for MongoDBMongoDB SoCal 2020: A Complete Methodology of Data Modeling for MongoDB
MongoDB SoCal 2020: A Complete Methodology of Data Modeling for MongoDB
 
MongoDB SoCal 2020: From Pharmacist to Analyst: Leveraging MongoDB for Real-T...
MongoDB SoCal 2020: From Pharmacist to Analyst: Leveraging MongoDB for Real-T...MongoDB SoCal 2020: From Pharmacist to Analyst: Leveraging MongoDB for Real-T...
MongoDB SoCal 2020: From Pharmacist to Analyst: Leveraging MongoDB for Real-T...
 
MongoDB SoCal 2020: Best Practices for Working with IoT and Time-series Data
MongoDB SoCal 2020: Best Practices for Working with IoT and Time-series DataMongoDB SoCal 2020: Best Practices for Working with IoT and Time-series Data
MongoDB SoCal 2020: Best Practices for Working with IoT and Time-series Data
 
MongoDB SoCal 2020: MongoDB Atlas Jump Start
 MongoDB SoCal 2020: MongoDB Atlas Jump Start MongoDB SoCal 2020: MongoDB Atlas Jump Start
MongoDB SoCal 2020: MongoDB Atlas Jump Start
 
MongoDB .local San Francisco 2020: Powering the new age data demands [Infosys]
MongoDB .local San Francisco 2020: Powering the new age data demands [Infosys]MongoDB .local San Francisco 2020: Powering the new age data demands [Infosys]
MongoDB .local San Francisco 2020: Powering the new age data demands [Infosys]
 
MongoDB .local San Francisco 2020: Using Client Side Encryption in MongoDB 4.2
MongoDB .local San Francisco 2020: Using Client Side Encryption in MongoDB 4.2MongoDB .local San Francisco 2020: Using Client Side Encryption in MongoDB 4.2
MongoDB .local San Francisco 2020: Using Client Side Encryption in MongoDB 4.2
 
MongoDB .local San Francisco 2020: Using MongoDB Services in Kubernetes: any ...
MongoDB .local San Francisco 2020: Using MongoDB Services in Kubernetes: any ...MongoDB .local San Francisco 2020: Using MongoDB Services in Kubernetes: any ...
MongoDB .local San Francisco 2020: Using MongoDB Services in Kubernetes: any ...
 
MongoDB .local San Francisco 2020: Go on a Data Safari with MongoDB Charts!
MongoDB .local San Francisco 2020: Go on a Data Safari with MongoDB Charts!MongoDB .local San Francisco 2020: Go on a Data Safari with MongoDB Charts!
MongoDB .local San Francisco 2020: Go on a Data Safari with MongoDB Charts!
 
MongoDB .local San Francisco 2020: From SQL to NoSQL -- Changing Your Mindset
MongoDB .local San Francisco 2020: From SQL to NoSQL -- Changing Your MindsetMongoDB .local San Francisco 2020: From SQL to NoSQL -- Changing Your Mindset
MongoDB .local San Francisco 2020: From SQL to NoSQL -- Changing Your Mindset
 
MongoDB .local San Francisco 2020: MongoDB Atlas Jumpstart
MongoDB .local San Francisco 2020: MongoDB Atlas JumpstartMongoDB .local San Francisco 2020: MongoDB Atlas Jumpstart
MongoDB .local San Francisco 2020: MongoDB Atlas Jumpstart
 
MongoDB .local San Francisco 2020: Tips and Tricks++ for Querying and Indexin...
MongoDB .local San Francisco 2020: Tips and Tricks++ for Querying and Indexin...MongoDB .local San Francisco 2020: Tips and Tricks++ for Querying and Indexin...
MongoDB .local San Francisco 2020: Tips and Tricks++ for Querying and Indexin...
 
MongoDB .local San Francisco 2020: A Complete Methodology of Data Modeling fo...
MongoDB .local San Francisco 2020: A Complete Methodology of Data Modeling fo...MongoDB .local San Francisco 2020: A Complete Methodology of Data Modeling fo...
MongoDB .local San Francisco 2020: A Complete Methodology of Data Modeling fo...
 
MongoDB .local San Francisco 2020: MongoDB Atlas Data Lake Technical Deep Dive
MongoDB .local San Francisco 2020: MongoDB Atlas Data Lake Technical Deep DiveMongoDB .local San Francisco 2020: MongoDB Atlas Data Lake Technical Deep Dive
MongoDB .local San Francisco 2020: MongoDB Atlas Data Lake Technical Deep Dive
 
MongoDB .local San Francisco 2020: Developing Alexa Skills with MongoDB & Golang
MongoDB .local San Francisco 2020: Developing Alexa Skills with MongoDB & GolangMongoDB .local San Francisco 2020: Developing Alexa Skills with MongoDB & Golang
MongoDB .local San Francisco 2020: Developing Alexa Skills with MongoDB & Golang
 
MongoDB .local Paris 2020: Realm : l'ingrédient secret pour de meilleures app...
MongoDB .local Paris 2020: Realm : l'ingrédient secret pour de meilleures app...MongoDB .local Paris 2020: Realm : l'ingrédient secret pour de meilleures app...
MongoDB .local Paris 2020: Realm : l'ingrédient secret pour de meilleures app...
 
MongoDB .local Paris 2020: Upply @MongoDB : Upply : Quand le Machine Learning...
MongoDB .local Paris 2020: Upply @MongoDB : Upply : Quand le Machine Learning...MongoDB .local Paris 2020: Upply @MongoDB : Upply : Quand le Machine Learning...
MongoDB .local Paris 2020: Upply @MongoDB : Upply : Quand le Machine Learning...
 
MongoDB .local Paris 2020: Les bonnes pratiques pour sécuriser MongoDB
MongoDB .local Paris 2020: Les bonnes pratiques pour sécuriser MongoDBMongoDB .local Paris 2020: Les bonnes pratiques pour sécuriser MongoDB
MongoDB .local Paris 2020: Les bonnes pratiques pour sécuriser MongoDB
 

Powerful Analysis with the Aggregation Pipeline

  • 1. # M D B l o c a l ASYA KAMSKY LEAD KNOW-IT-ALL MONGODB, INC @asya999 #askAsya PIPELINE POWER ANALYTICS WITH MONGODB AGGREGATION FRAMEWORK
  • 3.
  • 7.
  • 8.
  • 9.
  • 10.
  • 15. ps ax |grep mongod |head 1 *nix command line pipe PIPELINE
  • 16. $match $group | $sort| Input stream {} {} {}{} Result {} {}... PIPELINE MongoDB document pipeline
  • 17. Stage 1 Stage 2 Stage 3 Stage 4 {}{}{}{} {}{}{}{} DATA PIPELINE {}{}{}{} {"$stage":{ ... }} START Collection View Special stage
  • 18. {title: "The Great Gatsby", language: "English", subjects: "Long Island"} {title: "The Great Gatsby", language: "English", subjects: "New York"} {title: "The Great Gatsby", language: "English", subjects: "1920s"} {title: "The Great Gatsby", language: "English", subjects: [ "Long Island", "New York", "1920s"] }, {"$match":{"language":"English"}} $match { _id:"Long Island", count: 1 }, $group { _id: "New York", count: 2 }, $unwind { _id: "1920s", count: 1 }, $sort $skip$limit $project {"$unwind":"$subjects"} {"$group":{"_id":"$subjects", "count":{"$sum:1}} { _id: "Harlem", count: 1 }, { _id: "Long Island", count: 1 }, { _id: "New York", count: 2 }, { _id: "1920s", count: 1 }, {title: "Open City", language: "English", subjects: [ "New York" "Harlem" ] } { title: "The Great Gatsby", language: "English", subjects: [ "Long Island", "New York", "1920s"] }, { title: "War and Peace", language: "Russian", subjects: [ "Russia", "War of 1812", "Napoleon"] }, { title: "Open City", language: "English", subjects: [ "New York", "Harlem" ] }, {title: "Open City", language: "English", subjects: "New York"} {title: "Open City", language: "English", subjects: "Harlem"} { _id: "Harlem", count: 1 }, {"$sort:{"count":-1} {"$limit":3} {"$project":...}
  • 19.
  • 20.
  • 22. {title: "The Great Gatsby", language: "English". subjects: "Long Island"} {title: "The Great Gatsby", language: "English", subjects: "New York"} {title: "The Great Gatsby", language: "English", subjects: "1920s"} {title: "The Great Gatsby", language: "English", subjects: [ "Long Island", "New York", "1920s"] }, {"$match":{"language":"English"}} $match { _id:"Long Island", count: 1 }, $group { _id: "New York", count: 2 }, $unwind { _id: "1920s", count: 1 }, $sort $skip$limit $project {"$unwind":"$subjects"} {"$group":{"_id":"$subjects", "count":{"$sum:1}} { _id: "Harlem", count: 1 }, { _id:"LongIsland", count: 1 }, { _id: "New York", count: 2 }, { _id: "1920s", count: 1 }, {title: "Open City", language: "English", subjects: [ "New York" "Harlem" ] } { title: "The Great Gatsby", language: "English", subjects: [ "Long Island", "New York", "1920s"] }, { title: "War and Peace", language: "Russian", subjects: [ "Russia", "War of 1812", "Napoleon"] }, { title: "Open City", language: "English", subjects: [ "New York", "Harlem" ] }, {title: "Open City", language: "English", subjects: "New York"} {title: "Open City", language: "English", subjects: "Harlem"} { _id: "Harlem", count: 1 }, {"$sort:{"count":-1} {"$limit":3} {"$project":...} $group $sort 1
  • 25. db.books.aggregate([ {$match:{"language":"English"}}, {$unwind:"$subjects"}, {$group:{_id:"$subjects",count:{$sum:1}}}, {$sort:{count:-1}}, {$limit:3} ],{explain:true}) {"stages" : [ {"$cursor" : {"query" : { "language" : "English"}, "fields" : { "subjects" : 1,"_id" : 0} ... }}, {"$unwind" : {"path" : "$subjects"}}, {"$group" : {"_id" : "$subjects","count" : {"$sum" : {"$const" : 1}} }}, {"$sort" : { "sortKey" : {"count" : -1}, "limit" : NumberLong(3) }} ] }
  • 26. db.books.aggregate([ {$match:{"language":"English"}}, {$unwind:"$subjects"}, {$group:{_id:"$subjects",count:{$sum:1}}}, {$sort:{count:-1}}, {$limit:3} ],{explain:true}) {"stages" : [ {"$cursor" : {"query" : { "language" : "English"}, "fields" : { "subjects" : 1,"_id" : 0} ... }}, {"$unwind" : {"path" : "$subjects"}}, {"$group" : {"_id" : "$subjects","count" : {"$sum" : {"$const" : 1}} }}, {"$sort" : { "sortKey" : {"count" : -1}, "limit" : NumberLong(3) }} ] }
  • 27. db.books.aggregate([ {$match:{"language":"English"}}, {$unwind:"$subjects"}, {$group:{_id:"$subjects",count:{$sum:1}}}, {$sort:{count:-1}}, {$limit:3} ],{explain:true}) {"stages" : [ {"$cursor" : {"query" : { }, "fields" : { "subjects" : 1,"_id" : 0} ... }}, {"$unwind" : {"path" : "$subjects"}}, {"$group" : {"_id" : "$subjects","count" : {"$sum" : {"$const" : 1}} }}, {"$sort" : { "sortKey" : {"count" : -1}, "limit" : NumberLong(3) }} ] }
  • 29. db.books.aggregate([ {$unwind:"$subjects"}, {$match:{"language":"English"}}, {$group:{_id:"$subjects",count:{$sum:1}}}, {$sort:{count:-1}}, {$limit:3} ],{explain:true}) {"stages" : [ {"$cursor" : {"query" : { "language" : "English"}, "fields" : { "subjects" : 1,"_id" : 0} ... }}, {"$unwind" : {"path" : "$subjects"}}, {"$group" : {"_id" : "$subjects","count" : {"$sum" : {"$const" : 1}} }}, {"$sort" : { "sortKey" : {"count" : -1}, "limit" : NumberLong(3) }} ] }
  • 30. db.books.aggregate([ {$unwind:"$subjects"}, {$match:{"language":"English","subjects":/^[ABC]/}}, {$group:{_id:"$subjects",count:{$sum:1}}}, {$sort:{count:-1}}, {$limit:3} ],{explain:true}) {"stages" : [ {"$cursor" : {"query" : { "language" : "English"}, "fields" : { "subjects" : 1,"_id" : 0} ... }}, {"$unwind" : {"path" : "$subjects"}}, {"$match" : {"subjects" : {"$regex" : "^[ABC]"}}}, {"$group" : {"_id" : "$subjects","count" : {"$sum" : {"$const" : 1}}}}, {"$sort" : { "sortKey" : {"count" : -1}, "limit" : NumberLong(3) }} ] }
  • 31. db.books.aggregate([ {$unwind:"$subjects"}, {$match:{"language":"English","subjects":/^[ABC]/}}, {$group:{_id:"$subjects",count:{$sum:1}}}, {$sort:{count:-1}}, {$limit:3} ],{explain:true}) {"stages" : [ {"$cursor" : {"query" : { "language" : "English"}, "fields" : { "subjects" : 1,"_id" : 0} ... }}, {"$unwind" : {"path" : "$subjects"}}, {"$match" : {"subjects" : {"$regex" : "^[ABC]"}}}, {"$group" : {"_id" : "$subjects","count" : {"$sum" : {"$const" : 1}}}}, {"$sort" : { "sortKey" : {"count" : -1}, "limit" : NumberLong(3) }} ] }
  • 33. #MDBTOUR SCHEMA DISCOVERY & TRANSFORMATION
  • 34. {"body": { "VMESSAGE": { "072ade7d42d8": { "msgId": "bcd1d9", "date":1486546629585, "status": "accept", "comment": "hi" } } } }, {"body": { "VMESSAGE": { "595d0a56cff2": { "msgId": "595d0a", "date":1486566646197, "status": "reject", "comment": "no good" } } } }, { "body": { "VMESSAGE": { "52ffd09bf5b5": { "msgId": "1dadce", "date":1486568943752, "status": "accept" } } } } $project $addFields {"message": { "vid": "072ade7d42d8", "msgId": "bcd1d9", "date": 1486546629585, "status": "accept", "comment": "hi" } }, {"message": { "vid": "595d0a56cff2", "msgId": "595d0a", "date": 1486566646197, "status": "reject", "comment": "no good" } }, {"message": { "vid": "52ffd09bf5b5", "msgId": "1dadce", "date": 1486568943752, "status": "accept" } }
  • 35. {"body": { "VMESSAGE": { "072ade7d42d8": { "msgId": "bcd1d9", "date":1486546629585, "status": "accept", "comment": "hi" } } } }, {"body": { "VMESSAGE": { "595d0a56cff2": { "msgId": "595d0a", "date":1486566646197, "status": "reject", "comment": "no good" } } } }, { "body": { "VMESSAGE": { "52ffd09bf5b5": { "msgId": "1dadce", "date":1486568943752, "status": "accept" } } } } $addFields New Expressions (3.4.4, 3.6): {"$objectToArray": <object>} => array of k/v pairs {"$arrayToObject": <array of k/v pairs>} => object {"message": { "vid": "072ade7d42d8", "msgId": "bcd1d9", "date": 1486546629585, "status": "accept", "comment": "hi" } }, {"message": { "vid": "595d0a56cff2", "msgId": "595d0a", "date": 1486566646197, "status": "reject", "comment": "no good" } }, {"message": { "vid": "52ffd09bf5b5", "msgId": "1dadce", "date": 1486568943752, "status": "accept" } } Object "body.VMESSAGE": { "072ade7d42d8": { "messageId": "bcd1d9", "date": 1486546629585, "status": "accept", "comment": "hi" } } $ObjectToArray:"$body.VMESSAGE" [ { "k":"072ade7d42d8", "v": { "messageId": "bcd1d991", "date": 1486546629585, "status": "accept", "comment": "hi" } } ] Need array: [ {"k":"vid", "v":"072ade7d42d8"}, {"k":"messageId", "v":"bcd1d9"}, {"k":"date", "v":1486546629585, {"k":"status", "v":"accept"}, {"k":"comment", "v":"hi"} ]
  • 36. {"$addFields": { "message": { "$arrayToObject": ... {"$objectToArray":"$body.VMESSAGE"} } } } $addFields {"body": { "VMESSAGE": { "072ade7d42d8": { "msgId": "bcd1d9", "date":1486546629585, "status": "accept", "comment": "hi" } } } }, {"body": { "VMESSAGE": { "595d0a56cff2": { "msgId": "595d0a", "date":1486566646197, "status": "reject", "comment": "no good" } } } }, { "body": { "VMESSAGE": { "52ffd09bf5b5": { "msgId": "1dadce", "date":1486568943752, "status": "accept" } } } } {"message": { "vid": "072ade7d42d8", "msgId": "bcd1d9", "date": 1486546629585, "status": "accept", "comment": "hi" } }, {"message": { "vid": "595d0a56cff2", "msgId": "595d0a", "date": 1486566646197, "status": "reject", "comment": "no good" } }, {"message": { "vid": "52ffd09bf5b5", "msgId": "1dadce", "date": 1486568943752, "status": "accept" } }
  • 37. {"$addFields": { "bvm": {"$objectToArray":"$body.VMESSAGE"} } }, $addFields$addFields {"$addFields": { "msgarr": { } } }, {"$addFields": { "message": {"$arrayToObject": "$msgarr"} } } {"$addFields": { "bvm2": {"$arrayElemAt":["$bvm",0]} } }, {"$addFields": { "bvm": {"$objectToArray":"$bvm2.v"} } }, $addFields $addFields $addFields {"body": { "VMESSAGE": { "072ade7d42d8": { "msgId": "bcd1d9", "date":1486546629585, "status": "accept", "comment": "hi" } } } }, {"body": { "VMESSAGE": { "595d0a56cff2": { "msgId": "595d0a", "date":1486566646197, "status": "reject", "comment": "no good" } } } }, { "body": { "VMESSAGE": { "52ffd09bf5b5": { "msgId": "1dadce", "date":1486568943752, "status": "accept" } } } } {"message": { "vid": "072ade7d42d8", "msgId": "bcd1d9", "date": 1486546629585, "status": "accept", "comment": "hi" } }, {"message": { "vid": "595d0a56cff2", "msgId": "595d0a", "date": 1486566646197, "status": "reject", "comment": "no good" } }, {"message": { "vid": "52ffd09bf5b5", "msgId": "1dadce", "date": 1486568943752, "status": "accept" } }
  • 38. {"$addFields": { "bvm": {"$objectToArray":"$body.VMESSAGE"} } }, $addFields$addFields {"$addFields": { "msgarr": { "$concatArrays": [ [ { "k":"vid", "v":"$bvm2.k"} ], "$bvm" ] } } }, {"$addFields": { "message": {"$arrayToObject": "$msgarr"} } } {"$addFields": { "bvm2": {"$arrayElemAt":["$bvm",0]} } }, {"$addFields": { "bvm": {"$objectToArray":"$bvm2.v"} } }, $addFields $addFields $addFields {"body": { "VMESSAGE": { "072ade7d42d8": { "msgId": "bcd1d9", "date":1486546629585, "status": "accept", "comment": "hi" } } } }, {"body": { "VMESSAGE": { "595d0a56cff2": { "msgId": "595d0a", "date":1486566646197, "status": "reject", "comment": "no good" } } } }, { "body": { "VMESSAGE": { "52ffd09bf5b5": { "msgId": "1dadce", "date":1486568943752, "status": "accept" } } } } {"message": { "vid": "072ade7d42d8", "msgId": "bcd1d9", "date": 1486546629585, "status": "accept", "comment": "hi" } }, {"message": { "vid": "595d0a56cff2", "msgId": "595d0a", "date": 1486566646197, "status": "reject", "comment": "no good" } }, {"message": { "vid": "52ffd09bf5b5", "msgId": "1dadce", "date": 1486568943752, "status": "accept" } }
  • 39. $addFields {"$addFields":{ "message":{ "$arrayToObject":{ "$let":{ "vars":{ "elem": {"$arrayElemAt:[ {"$objectToArray":"$body.VMESSAGE"}, 0 ]} }, "in":{"$concatArrays":[ [ { k: "vid", v: "$$elem.k" } ], {$objectToArray:"$$elem.v"} ]} }} } }} {"body": { "VMESSAGE": { "072ade7d42d8": { "msgId": "bcd1d9", "date":1486546629585, "status": "accept", "comment": "hi" } } } }, {"body": { "VMESSAGE": { "595d0a56cff2": { "msgId": "595d0a", "date":1486566646197, "status": "reject", "comment": "no good" } } } }, { "body": { "VMESSAGE": { "52ffd09bf5b5": { "msgId": "1dadce", "date":1486568943752, "status": "accept" } } } } {"message": { "vid": "072ade7d42d8", "msgId": "bcd1d9", "date": 1486546629585, "status": "accept", "comment": "hi" } }, {"message": { "vid": "595d0a56cff2", "msgId": "595d0a", "date": 1486566646197, "status": "reject", "comment": "no good" } }, {"message": { "vid": "52ffd09bf5b5", "msgId": "1dadce", "date": 1486568943752, "status": "accept" } }
  • 40. $addFields {"$addFields":{ "message":{ "$arrayToObject":{ "$let":{ "vars":{ "elem": {"$arrayElemAt:[ {"$objectToArray":"$body.VMESSAGE"}, 0 ]} }, "in":{"$concatArrays":[ [ { k: "vid", v: "$$elem.k" } ], {$objectToArray:"$$elem.v"} ]} }} } }} {"body": { "VMESSAGE": { "072ade7d42d8": { "msgId": "bcd1d9", "date":1486546629585, "status": "accept", "comment": "hi" } } } }, {"body": { "VMESSAGE": { "595d0a56cff2": { "msgId": "595d0a", "date":1486566646197, "status": "reject", "comment": "no good" } } } }, { "body": { "VMESSAGE": { "52ffd09bf5b5": { "msgId": "1dadce", "date":1486568943752, "status": "accept" } } } } {"message": { "vid": "072ade7d42d8", "msgId": "bcd1d9", "date": 1486546629585, "status": "accept", "comment": "hi" } }, {"message": { "vid": "595d0a56cff2", "msgId": "595d0a", "date": 1486566646197, "status": "reject", "comment": "no good" } }, {"message": { "vid": "52ffd09bf5b5", "msgId": "1dadce", "date": 1486568943752, "status": "accept" } }
  • 41. $addFields {"$addFields":{ "message":{ "$arrayToObject":{ "$let":{ "vars":{ "elem": {"$arrayElemAt:[ {"$objectToArray":"$body.VMESSAGE"}, 0 ]} }, "in":{"$concatArrays":[ [ { k: "vid", v: "$$elem.k" } ], {$objectToArray:"$$elem.v"} ]} }} } }} {"body": { "VMESSAGE": { "072ade7d42d8": { "msgId": "bcd1d9", "date":1486546629585, "status": "accept", "comment": "hi" } } } }, {"body": { "VMESSAGE": { "595d0a56cff2": { "msgId": "595d0a", "date":1486566646197, "status": "reject", "comment": "no good" } } } }, { "body": { "VMESSAGE": { "52ffd09bf5b5": { "msgId": "1dadce", "date":1486568943752, "status": "accept" } } } } {"message": { "vid": "072ade7d42d8", "msgId": "bcd1d9", "date": 1486546629585, "status": "accept", "comment": "hi" } }, {"message": { "vid": "595d0a56cff2", "msgId": "595d0a", "date": 1486566646197, "status": "reject", "comment": "no good" } }, {"message": { "vid": "52ffd09bf5b5", "msgId": "1dadce", "date": 1486568943752, "status": "accept" } }
  • 46. #MDBTOUR array manipulations $map input: array output: array $filter input: array output: subset of array $reduce input: array output: anything you want
  • 47. #MDBTOUR array manipulations: "arr":[{"a":1},{"a":99},{"a":5},{"a":3}] {"$map":{ "input":"$arr", "in":"$$this" }} {"$map":{ "input":"$arr", "as":"eachElem", "in":{"b":"$$eachElem.a"} }} {"$map":{ "input":{"$range":[0,{"$size":"$arr"}]}, "as":"index", "in":{"c":{"$arrayElemAt":["$arr.a","$$index"]}} }} "a" 1 "a" 99 "a" 5 "a" 3 "b" 1 "b" 99 "b" 5 "b" 3 "c" 1 "c" 99 "c" 5 "c" 3 "a" 1 "a" 99 "a" 5 "a" 3 "a" 1 "a" 99 "a" 5 "a" 3 0 1 2 3 {"$map":{ "input":"$arr", "as":"var", "in":"$$var" }} $map {"$map":{ "input":"$arr.a", "as":"eachElem", "in":{"b":"$$eachElem"}}} 1 99 5 3
  • 53. #MDBTOUR encapsulate complexity Functions for expressions reverseArray=function(input){ return{"$reduce":{ "input":input, "intialValue":[], "in":{"$concatArrays":[ ["$$this"], "$$value" ]} }}; }; db.c.aggregate([{"$addFields":{ "revArray":reverseArray("$origArray") }}])
  • 54. #MDBTOUR encapsulate complexity Functions for expressions sortArray=function(inputArray,sortField="",asc=false) { varsuffix=""; varmaxF=MaxKey; varminF=MinKey; db.c.aggregate([{"$addFields":{ "sortedArray":sortArray("$origArray") }}])
  • 57. {$match:{ts:{$gte:start,$lt:end}}}, {$sort:{ts:1}}, {$group:{_id:"$user",ips:{$push:{ip:"$ipaddr", ts:"$ts"}}}}, $sort$match $group start=ISODate("...") end=ISODate("...") { user: "303900", ipaddr: "71.56.112.56", ts:ISODate("2017-05-08T...") } { _id: "303900", ips: [ {ip:"71.56.112.56", ts:ISODate("2017-05-08T08:54:04Z") }, {ip:"71.56.112.56", ts:ISODate("2017-05-09T09:01:11Z") }, {ip:"12.130.117.87", ts:ISODate("2017-05-09T09:04:59Z") } ]}
  • 58. $sort$match $group $addFields $match start=ISODate("...") end=ISODate("...") { user: "303900", ipaddr: "71.56.112.56", ts:ISODate("2017-05-08T...") } $project {_id:"303900", ips:[ {ip:"71.56.112.56", ts:ISODate("2017-05-08T...") }, {ip:"71.56.112.56", ts:ISODate("2017-05-09T...") }, {ip:"12.130.117.87", ts:ISODate("2017-05-09T...") } ]} {$match:{ts:{$gte:start,$lt:end}}}, {$sort:{ts:1}}, {$group:{_id:"$user",ips:{$push:{ip:"$ipaddr", ts:"$ts"}}}}, {$addFields:{diffs: {$filter:{ input:{$map:{ input: {$range:[0,{$subtract:[{$size:"$ips"},1]}]}, as:"i", in:{$let:{vars:{ip1:{$arrayElemAt:["$ips","$$i"]}, ip2:{$arrayElemAt:["$ips",{$add:["$$i",1]}]}}, in:{ diff:{$divide:[{$subtract:["$$ip2.ts","$$ip1.ts"]},60000]}, ip1:"$$ip1.ip", t1:"$$ip1.ts", ip2:"$$ip2.ip", t2:"$$ip2.ts" }}}}}, cond:{$and:[{$lt:["$$this.diff",10]},{$ne:["$$this.ip1","$$this.ip2"]}]} }}}},
  • 59. $sort$match $group $addFields $match start=ISODate("...") end=ISODate("...") { user: "303900", ipaddr: "71.56.112.56", ts:ISODate("2017-05-08T...") } $project {_id:"303900", ips:[ {ip:"71.56.112.56", ts:ISODate("2017-05-08T...") }, {ip:"71.56.112.56", ts:ISODate("2017-05-09T...") }, {ip:"12.130.117.87", ts:ISODate("2017-05-09T...") } ]} {$match:{ts:{$gte:start,$lt:end}}}, {$sort:{ts:1}}, {$group:{_id:"$user",ips:{$push:{ip:"$ipaddr", ts:"$ts"}}}}, {$addFields:{diffs: {$filter:{ input:{$map:{ input: {$range:[0,{$subtract:[{$size:"$ips"},1]}]}, as:"i", in:{$let:{vars:{ip1:{$arrayElemAt:["$ips","$$i"]}, ip2:{$arrayElemAt:["$ips",{$add:["$$i",1]}]}}, in:{ diff:{$divide:[{$subtract:["$$ip2.ts","$$ip1.ts"]},60000]}, ip1:"$$ip1.ip", t1:"$$ip1.ts", ip2:"$$ip2.ip", t2:"$$ip2.ts" }}}}}, cond:{$and:[{$lt:["$$this.diff",10]},{$ne:["$$this.ip1","$$this.ip2"]}]} }}}}, {$match:{"diffs":{$ne:[]}}}, {$project:{_id:0, user:"$_id", suspectLogins:"$diffs"}}
  • 60. $sort$match $group $addFields $match start=ISODate("...") end=ISODate("...") { user: "303900", ipaddr: "71.56.112.56", ts:ISODate("2017-05-08T...") } $project {$match:{ts:{$gte:start,$lt:end}}}, {$sort:{ts:1}}, {$group:{_id:"$user",ips:{$push:{ip:"$ipaddr", ts:"$ts"}}}}, {$addFields:{diffs: {$filter:{ input:{$map:{ input: {$range:[0,{$subtract:[{$size:"$ips"},1]}]}, as:"i", in:{$let:{vars:{ip1:{$arrayElemAt:["$ips","$$i"]}, ip2:{$arrayElemAt:["$ips",{$add:["$$i",1]}]}}, in:{ diff:{$divide:[{$subtract:["$$ip2.ts","$$ip1.ts"]},60000]}, ip1:"$$ip1.ip", t1:"$$ip1.ts", ip2:"$$ip2.ip", t2:"$$ip2.ts" }}}}}, cond:{$and:[{$lt:["$$this.diff",10]},{$ne:["$$this.ip1","$$this.ip2"]}]} }}}}, {$match:{"diffs":{$ne:[]}}}, {$project:{_id:0, user:"$_id", suspectLogins:"$diffs"}} {"user":"35237073", "suspectLogins":[ {"diff":4.8333333333, "ip1":"106.220.151.16", "t1":"2017-05-08T06:58", "ip2":"223.182.113.15" "t2":"2017-05-08T07:03" }, {"diff":8.3, "ip1":"223.182.113.15", "t1":"2017-05-08T07:03", "ip2":"49.206.217.26", "t2":"2017-05-08T07:11" } ] }
  • 61. $sort$match $group $addFields $match $project {$match:{ts:{$gte:start,$lt:end}}}, {$sort:{ts:1}}, {$group:{_id:"$user",ips:{$push:{ip:"$ipaddr", ts:"$ts"}}}}, {$addFields:{diffs: {$filter:{ input:{$map:{ input: {$range:[0,{$subtract:[{$size:"$ips"},1]}]}, as:"i", in:{$let:{vars:{ip1:{$arrayElemAt:["$ips","$$i"]}, ip2:{$arrayElemAt:["$ips",{$add:["$$i",1]}]}}, in:{ diff:{$divide:[{$subtract:["$$ip2.ts","$$ip1.ts"]},60000]}, ip1:"$$ip1.ip", t1:"$$ip1.ts", ip2:"$$ip2.ip", t2:"$$ip2.ts" }}}}}, cond:{$and:[{$lt:["$$this.diff",10]},{$ne:["$$this.ip1","$$this.ip2"]}]} }}}}, {$match:{"diffs":{$ne:[]}}}, {$project:{_id:0, user:"$_id", suspectLogins:"$diffs"}} start=ISODate("...") end=ISODate("...") { user: "303900", ipaddr: "71.56.112.56", ts:ISODate("2017-05-08T...") } {"user":"35237073", "suspectLogins":[ {"diff":4.8333333333, "ip1":"106.220.151.16", "t1":"2017-05-08T06:58", "ip2":"223.182.113.15" "t2":"2017-05-08T07:03" }, {"diff":8.3, "ip1":"223.182.113.15", "t1":"2017-05-08T07:03", "ip2":"49.206.217.26", "t2":"2017-05-08T07:11" } ] }
  • 62. $sort$match $group $addFields $match start=ISODate("...") end=ISODate("...") { user: "303900", ipaddr: "71.56.112.56", ts:ISODate("2017-05-08T...") } $addFields $match $proj {$match:{ts:{$gte:start,$lt:end}}}, {$sort:{ts:1}}, {$group:{_id:"$user",ips:{$push:{ip:"$ipaddr", ts:"$ts"}}}}, {$addFields:{diffIpNum:{$size:{$setUnion:"$ips.ip"}}}}, {$match:{diffIpNum:{$gt:1}}}, {$addFields:{diffs: {$filter:{ input:{$map:{ input: {$range:[0,{$subtract:[{$size:"$ips"},1]}]}, as:"i", in:{$let:{vars:{ip1:{$arrayElemAt:["$ips","$$i"]}, ip2:{$arrayElemAt:["$ips",{$add:["$$i",1]}]}}, in:{ diff:{$divide:[{$subtract:["$$ip2.ts","$$ip1.ts"]},60000]}, ip1:"$$ip1.ip", t1:"$$ip1.ts", ip2:"$$ip2.ip", t2:"$$ip2.ts" }}}}}, cond:{$and:[{$lt:["$$this.diff",10]},{$ne:["$$this.ip1","$$this.ip2"]}]} }}}}, {$match:{"diffs":{$ne:[]}}}, {$project:{_id:0, user:"$_id", suspectLogins:"$diffs"}} {"user":"35237073", "suspectLogins":[ {"diff":4.8333333333, "ip1":"106.220.151.16", "t1":"2017-05-08T06:58", "ip2":"223.182.113.15" "t2":"2017-05-08T07:03" }, {"diff":8.3, "ip1":"223.182.113.15", "t1":"2017-05-08T07:03", "ip2":"49.206.217.26", "t2":"2017-05-08T07:11" } ] }
  • 63. $sort$match $group $match start=ISODate("...") end=ISODate("...") { user: "303900", ipaddr: "71.56.112.56", ts:ISODate("2017-05-08T...") } $addFields $match $project {$match:{ts:{$gte:start,$lt:end}}}, {$sort:{ts:1}}, {$group:{_id:"$user",ips:{$push:{ip:"$ipaddr", ts:"$ts"}}, diffIps:{$addToSet:"$ipaddr"}}}, {$match:{"diffIps.1":{$exists:true}}}, {$addFields:{diffs: {$filter:{ input:{$map:{ input: {$range:[0,{$subtract:[{$size:"$ips"},1]}]}, as:"i", in:{$let:{vars:{ip1:{$arrayElemAt:["$ips","$$i"]}, ip2:{$arrayElemAt:["$ips",{$add:["$$i",1]}]}}, in:{ diff:{$divide:[{$subtract:["$$ip2.ts","$$ip1.ts"]},60000]}, ip1:"$$ip1.ip", t1:"$$ip1.ts", ip2:"$$ip2.ip", t2:"$$ip2.ts" }}}}}, cond:{$and:[{$lt:["$$this.diff",10]},{$ne:["$$this.ip1","$$this.ip2"]}]} }}}}, {$match:{"diffs":{$ne:[]}}}, {$project:{_id:0, user:"$_id", suspectLogins:"$diffs"}} {"user":"35237073", "suspectLogins":[ {"diff":4.8333333333, "ip1":"106.220.151.16", "t1":"2017-05-08T06:58", "ip2":"223.182.113.15" "t2":"2017-05-08T07:03" }, {"diff":8.3, "ip1":"223.182.113.15", "t1":"2017-05-08T07:03", "ip2":"49.206.217.26", "t2":"2017-05-08T07:11" } ] }
  • 64. $sort$match $group start=ISODate("...") end=ISODate("...") { user: "303900", ipaddr: "71.56.112.56", ts:ISODate("2017-05-08T...") } {$match:{ts:{$gte:start,$lt:end}}}, {$sort:{ts:1}}, {$group:{_id:"$user",ips:{$push:{ip:"$ipaddr", ts:"$ts"}}, diffIps:{$addToSet:"$ipaddr"}}}, {$match:{"diffIps.1":{$exists:true}}}, {$addFields:{diffs: {$filter:{ input:{$map:{ input: {$range:[0,{$subtract:[{$size:"$ips"},1]}]}, as:"i", in:{$let:{vars:{ip1:{$arrayElemAt:["$ips","$$i"]}, ip2:{$arrayElemAt:["$ips",{$add:["$$i",1]}]}}, in:{ diff:{$divide:[{$subtract:["$$ip2.ts","$$ip1.ts"]},60000]}, ip1:"$$ip1.ip", t1:"$$ip1.ts", ip2:"$$ip2.ip", t2:"$$ip2.ts" }}}}}, cond:{$and:[{$lt:["$$this.diff",10]},{$ne:["$$this.ip1","$$this.ip2"]}]} }}}}, {$match:{"diffs":{$ne:[]}}}, {$project:{_id:0, user:"$_id", suspectLogins:"$diffs"}} {"user":"35237073", "suspectLogins":[ {"diff":4.8333333333, "ip1":"106.220.151.16", "t1":"2017-05-08T06:58", "ip2":"223.182.113.15" "t2":"2017-05-08T07:03" }, {"diff":8.3, "ip1":"223.182.113.15", "t1":"2017-05-08T07:03", "ip2":"49.206.217.26", "t2":"2017-05-08T07:11" } ] } $match $addFields $match $project
  • 65. $sort$match $group start=ISODate("...") end=ISODate("...") { user: "303900", ipaddr: "71.56.112.56", ts:ISODate("2017-05-08T...") } {$match:{ts:{$gte:start,$lt:end}}}, {$sort:{ts:1}}, {$group:{_id:"$user",ips:{$push:{ip:"$ipaddr", ts:"$ts"}}, diffIps:{$addToSet:"$ipaddr"}}}, {$match:{"diffIps.1":{$exists:true}}}, {$addFields:{diffs: {$filter:{ input:{$map:{ input: {$range:[0,{$subtract:[{$size:"$ips"},1]}]}, as:"i", in:{$let:{vars:{ip1:{$arrayElemAt:["$ips","$$i"]}, ip2:{$arrayElemAt:["$ips",{$add:["$$i",1]}]}}, in:{ diff:{$cond:{ }}, ip1:"$$ip1.ip", t1:"$$ip1.ts", ip2:"$$ip2.ip", t2:"$$ip2.ts" }}}}}, cond:{$and:[{$lt:["$$this.diff",10]},{$ne:["$$this.ip1","$$this.ip2"]}]} }}}}, {$match:{"diffs":{$ne:[]}}}, {$project:{_id:0, user:"$_id", suspectLogins:"$diffs"}} {"user":"35237073", "suspectLogins":[ {"diff":4.8333333333, "ip1":"106.220.151.16", "t1":"2017-05-08T06:58", "ip2":"223.182.113.15" "t2":"2017-05-08T07:03" }, {"diff":8.3, "ip1":"223.182.113.15", "t1":"2017-05-08T07:03", "ip2":"49.206.217.26", "t2":"2017-05-08T07:11" } ] } $match $addFields $match $project
  • 66. $sort$match $group start=ISODate("...") end=ISODate("...") { user: "303900", ipaddr: "71.56.112.56", ts:ISODate("2017-05-08T...") } {$match:{ts:{$gte:start,$lt:end}}}, {$sort:{ts:1}}, {$group:{_id:"$user",ips:{$push:{ip:"$ipaddr", ts:"$ts"}}, diffIps:{$addToSet:"$ipaddr"}}}, {$match:{"diffIps.1":{$exists:true}}}, {$addFields:{diffs: {$filter:{ input:{$map:{ input: {$range:[0,{$subtract:[{$size:"$ips"},1]}]}, as:"i", in:{$let:{vars:{ip1:{$arrayElemAt:["$ips","$$i"]}, ip2:{$arrayElemAt:["$ips",{$add:["$$i",1]}]}}, in:{ diff:{$cond:{ if:{$ne:["$$this.ip1","$$this.ip2"]}, then:{$divide:[{$subtract:["$$ip2.ts","$$ip1.ts"]},60000]}]}, else: 9999 }}, ip1:"$$ip1.ip", t1:"$$ip1.ts", ip2:"$$ip2.ip", t2:"$$ip2.ts" }}}}}, cond:{$and:[{$lt:["$$this.diff",10]},{$ne:["$$this.ip1","$$this.ip2"]}]} }}}}, {$match:{"diffs":{$ne:[]}}}, {$project:{_id:0, user:"$_id", suspectLogins:"$diffs"}} {"user":"35237073", "suspectLogins":[ {"diff":4.8333333333, "ip1":"106.220.151.16", "t1":"2017-05-08T06:58", "ip2":"223.182.113.15" "t2":"2017-05-08T07:03" }, {"diff":8.3, "ip1":"223.182.113.15", "t1":"2017-05-08T07:03", "ip2":"49.206.217.26", "t2":"2017-05-08T07:11" } ] } $match $addFields $match $project
  • 67. $sort$match $group start=ISODate("...") end=ISODate("...") { user: "303900", ipaddr: "71.56.112.56", ts:ISODate("2017-05-08T...") } {$match:{ts:{$gte:start,$lt:end}}}, {$sort:{ts:1}}, {$group:{_id:"$user",ips:{$push:{ip:"$ipaddr", ts:"$ts"}}, diffIps:{$addToSet:"$ipaddr"}}}, {$match:{"diffIps.1":{$exists:true}}}, {$addFields:{diffs: {$filter:{ input:{$map:{ input: {$range:[0,{$subtract:[{$size:"$ips"},1]}]}, as:"i", in:{$let:{vars:{ip1:{$arrayElemAt:["$ips","$$i"]}, ip2:{$arrayElemAt:["$ips",{$add:["$$i",1]}]}}, in:{ diff:{$cond:{ if:{$ne:["$$this.ip1","$$this.ip2"]}, then:{$divide:[{$subtract:["$$ip2.ts","$$ip1.ts"]},60000]}]}, else: 9999 }}, ip1:"$$ip1.ip", t1:"$$ip1.ts", ip2:"$$ip2.ip", t2:"$$ip2.ts" }}}}}, cond:{$and:[{$lt:["$$this.diff",10]},{$ne:["$$this.ip1","$$this.ip2"]}]} }}}}, {$match:{"diffs":{$ne:[]}}}, {$project:{_id:0, user:"$_id", suspectLogins:"$diffs"}} {"user":"35237073", "suspectLogins":[ {"diff":4.8333333333, "ip1":"106.220.151.16", "t1":"2017-05-08T06:58", "ip2":"223.182.113.15" "t2":"2017-05-08T07:03" }, {"diff":8.3, "ip1":"223.182.113.15", "t1":"2017-05-08T07:03", "ip2":"49.206.217.26", "t2":"2017-05-08T07:11" } ] } $match $addFields $match $project
  • 68. $sort$match $group start=ISODate("...") end=ISODate("...") { user: "303900", ipaddr: "71.56.112.56", ts:ISODate("2017-05-08T...") } {$match:{ts:{$gte:start,$lt:end}}}, {$sort:{ts:1}}, {$group:{_id:"$user",ips:{$push:{ip:"$ipaddr", ts:"$ts"}}, diffIps:{$addToSet:"$ipaddr"}}}, {$match:{"diffIps.1":{$exists:true}}}, {$addFields:{diffs: {$filter:{ input:{$map:{ input: {$range:[0,{$subtract:[{$size:"$ips"},1]}]}, as:"i", in:{$let:{vars:{ip1:{$arrayElemAt:["$ips","$$i"]}, ip2:{$arrayElemAt:["$ips",{$add:["$$i",1]}]}}, in:{ diff:{$cond:{ if:{$ne:["$$this.ip1","$$this.ip2"]}, then:{$divide:[{$subtract:["$$ip2.ts","$$ip1.ts"]},60000]}]}, else: 9999 }}, ip1:"$$ip1.ip", t1:"$$ip1.ts", ip2:"$$ip2.ip", t2:"$$ip2.ts" }}}}}, cond:{$lt:["$$this.diff",10]} }}}}, {$match:{"diffs":{$ne:[]}}}, {$project:{_id:0, user:"$_id", suspectLogins:"$diffs"}} {"user":"35237073", "suspectLogins":[ {"diff":4.8333333333, "ip1":"106.220.151.16", "t1":"2017-05-08T06:58", "ip2":"223.182.113.15" "t2":"2017-05-08T07:03" }, {"diff":8.3, "ip1":"223.182.113.15", "t1":"2017-05-08T07:03", "ip2":"49.206.217.26", "t2":"2017-05-08T07:11" } ] } $match $addFields $match $project
  • 69. #MDBTOUR POWERFUL AGGREGATIONS understand stages • Best order for performance • Avoid unnecessary "blocking" • keep "streaming" • Maximize use of indexes • early stages get the index! • Liberally check explain() output understand expressions • Schema manipulation • Array transformation use functions • Readable, debug-able, reusable
  • 70. #MDBTOUR THE FUTURE OF AGGREGATION Better performance & optimizations More stages & expressions More options for output Compass helper for aggregate
  • 72. # M D B l o c a l THANK YOU! https://github.com/asya999/mdbw17

Editor's Notes

  1. store data the way you need to retrieve it, after the initial design, you need to retrieve the data again, but this time not to the way you wrote it, if the data is important, you will need to analyze it – analyze your success, analyze your failures, it's hard to anticipate all the kinds of analytics you want to do.
  2. what are the options to analyze the data you've store in MongoDB? High level: you have three options.
  3. first one is the best when you need the aggregated results super fast – but it requires you know all of them in advance, and you need a crystal ball for that. Anyway, that topic is "schema design".
  4. next you can take the data and move it to another system for analysis.
  5. of course when I say another system I usually mean hadoop or spark, some massively parallel cluster that can do massive fancy computations super duper fast. But to see a potential downside of this approach, let me use an analogy (if you've heard my talks before, you guys know I love analogies)
  6. I've been doing some home improvements and I'm a DIY kind of gal – now for every task there are lots of ways that it can be done and all of them might be "right" they just have different trade-offs. Let's say I have to cut a piece of wood – there are lots of tools that can do it, at many different price points...
  7. Realistically I had two options. I could go to the local HW store where they have a big wood cutting machine and it could cut my piece of wood in seconds. It'd probably only cost me a couple of bucks. Or I can stay home and cut it myself with a saw I got for $2 on a garage sale. It takes longer – maybe 5 minutes instead of 5 seconds, but overall latency is still better because I saved myself a trip to the store.
  8. similarly when your data is in MongoDB, to get it analyzed in the massive other cluster you already have...
  9. So even though that cluster can analyze your data super fast, the extra latency of moving the data over might make this the wrong choice IF
  10. *IF* you can do the same analysis right in MongoDB. And that's our option three – do the aggregation in MongoDB.
  11. aggregation in MongoDB is not just for analysis of the data that you stored in the DB aggregation allows you to access system data we at MongoDB are more and more choosing to return the data about the system to you as an output of an aggregation stage in the aggregation pipeline .
  12. what is aggregation stage & what is aggregation pipeline and what is the language for transforming results, including a number of stages, expressions and accumulators being advanced talk, I’m going to make this part very short. If you get lost, check out the docs and more basic tutorials...
  13. language for transforming data/results, including a number of stages, expressions and accumulators. why do we call it a “pipe” or pipeline? as in we let you pipe your data through some kind of “analysis”
  14. instead of *nix commands, it's stages and what's going through them are documents.
  15. what does pipeline start with? documents. Where do they come from? Coll, view, special. Each stage has documents enter and documents exit from it. stages themselves are specified as documents.
  16. documents flow how many enter, do they get changed/transformed
  17. 22 stages
  18. way to think of them is in terms of how they act on documents coming into them to turn them into documents coming out of them.
  19. group: decrease input: system info transform (a little or a lot) decrease in absolute numbers or based on conditional increase (usually)
  20. follow the first document through the pipeline BLOCKING STAGES
  21. blocking stages. remember is "you send stages to the system to tell it what you want to accomplish, the stages it runs may be different because it's allowed to shuffle things around in order to optimize the performance."
  22. five stages in, four "things" – last one: $sort+$limit
  23. $cursor stage – pipeline starts at unwind, $cursor just tells you what the *source* of aggregation is. It's a collection, rather a cursor that you get when you do a *find* on a collection, and the find has whatever query we can push down to it... agg starts at blue arrow!!! what if there is no $match?
  24. if no $match empty.
  25. what if we remove $match
  26. NEXT: $PROJECT, word about PROJECT when the aggregation asks the query subsystem for the documents, not only does it try to push down the query (and the sort)
  27. when the aggregation asks the query subsystem for the documents, not only does it try to push down the query (and the sort) figures out which fields are necessary to accomplish the entire pipeline and only asks for those fields. So usually you do NOT need to add a $project just to exclude some fields.
  28. so that was stages, what about what you can do inside each stage? I'll go over some of the more powerful expressions (schema, arrays)
  29. all examples are in github. This one is from SO question
  30. 3.6 will have $mergeObjects but that's okay, we can simulate that with object to array and array manipulations
  31. for clarity, don't be afraid to split a stage into multiple $addFields stages for clarity, readability and correctness! you can always merge them later if you don't want anyone else to be able to understand what you are doing  now here in the middle we need to merge together something to get the result array, so ...
  32. we'll be using "$concatArrays" for this purpose. you can always merge them later if you don't want anyone else to be able to understand what you are doing 
  33. what does this look like as one stage? turns out it's quite readable!
  34. the reason is I use "$let" to define a variable "elem"
  35. use its components – but this is the same thing I did as five stages before.
  36. so we already saw that I had to do some array manipulations for schema transformations – arrays are big strength of MongoDB so we want to know how to handle them in aggregations in ways that allow you to avoid unnecessary "$unwind"ing and re-grouping of large arrays.
  37. of over 100 expressions, over a dozen for dealing with arrays.
  38. we used these, but the most important and powerful ones are
  39. just like stages output a certain number of documents relative to how many they get as input, so do these array expressions.
  40. $map:{input:"$array", output array of same size. gives you each element and it outputs a single "thing" for each element (I.e. Array in, array out) $filter outputs subset of exact same array it was passed in – for each element it outputs it if condition true. $reduce input array, output single value - which can be an array, a document (array of documents) or a scalar value.
  41. no matter what I do I'll get back out four elements, but I can do it a number of different ways
  42. $filter – condition. could get back [] or entire input array.
  43. reduce allows you to specify what your result looks like at the beginning, before you iterated over any elements of "input" array
  44. that $reduce expression is what {$sum:[ ]} does.
  45. Notice that the second reduce expression is equivalent to $reverseArray. what that means is that you can write any array processing expression yourself using these expressions. The additional ones we give you are just syntactic sugar.
  46. obviously this is just an example as there exists $reverseArray expression, but if it didn't then you could express it with $reduce not just array expressions, but many others – calculations, etc.
  47. obviously this is just an example as there exists $reverseArray expression, but if it didn't then you could express it with $reduce
  48. Have all login records with time, and IP address they logged in from. Would like to check for a particular time period, did any user log in from more than one IP within some interval
  49. Have all login records with time, and IP address they logged in from. Would like to check for a particular time period, did any user log in from more than one IP within some interval
  50. Have all login records with time, and IP address they logged in from. Would like to check for a particular time period, did any user log in from more than one IP within some interval
  51. Have all login records with time, and IP address they logged in from. Would like to check for a particular time period, did any user log in from more than one IP within some interval
  52. Have all login records with time, and IP address they logged in from. Would like to check for a particular time period, did any user log in from more than one IP within some interval
  53. Have all login records with time, and IP address they logged in from. Would like to check for a particular time period, did any user log in from more than one IP within some interval
  54. Have all login records with time, and IP address they logged in from. Would like to check for a particular time period, did any user log in from more than one IP within some interval
  55. Have all login records with time, and IP address they logged in from. Would like to check for a particular time period, did any user log in from more than one IP within some interval
  56. Have all login records with time, and IP address they logged in from. Would like to check for a particular time period, did any user log in from more than one IP within some interval
  57. Have all login records with time, and IP address they logged in from. Would like to check for a particular time period, did any user log in from more than one IP within some interval
  58. Have all login records with time, and IP address they logged in from. Would like to check for a particular time period, did any user log in from more than one IP within some interval
  59. Have all login records with time, and IP address they logged in from. Would like to check for a particular time period, did any user log in from more than one IP within some interval
  60. Have all login records with time, and IP address they logged in from. Would like to check for a particular time period, did any user log in from more than one IP within some interval
  61. Have all login records with time, and IP address they logged in from. Would like to check for a particular time period, did any user log in from more than one IP within some interval
  62. In terms of performance, you send stages to the system to tell it what you want to accomplish, the stages it runs may be different because it's allowed to shuffle things around in order to optimize the performance.