I have a situation where I have got one result from aggregation where I am getting data in this format.
{
"_id" : ObjectId("5a42432d69cbfed9a410e8ad"),
"bacId" : "BAC0023444",
"cardId" : "2",
"defaultCardOrder" : "2",
"alias" : "Finance",
"label" : "Finance",
"for" : "",
"cardTooltip" : {
"enable" : true,
"text" : ""
},
"dataBlocks" : [
{
"defaultBlockOrder" : "1",
"blockId" : "1",
"data" : "0"
},
{
"defaultBlockOrder" : "2",
"blockId" : "2",
"data" : "0"
},
{
"defaultBlockOrder" : "3",
"blockId" : "3",
"data" : "0"
}
],
"templateBlocks" : [
{
"blockId" : "1",
"label" : "Gross Profit",
"quarter" : "",
"data" : "",
"dataType" : {
"typeId" : "2"
},
"tooltip" : {
"enable" : true,
"text" : ""
}
},
{
"blockId" : "2",
"label" : "Profit Forecast",
"quarter" : "",
"data" : "",
"dataType" : {
"typeId" : "2"
},
"tooltip" : {
"enable" : true,
"text" : ""
}
},
{
"blockId" : "3",
"label" : "Resource Billing",
"quarter" : "",
"data" : "",
"dataType" : {
"typeId" : "2"
},
"tooltip" : {
"enable" : true,
"text" : ""
}
}
]
},
{
"_id" : ObjectId("5a42432d69cbfed9a410e8ad"),
"bacId" : "BAC0023444",
"cardId" : "3",
"defaultCardOrder" : "3",
"alias" : "Staffing",
"label" : "Staffing",
"for" : "",
"cardTooltip" : {
"enable" : true,
"text" : ""
},
"dataBlocks" : [
{
"defaultBlockOrder" : "1",
"blockId" : "1",
"data" : "1212"
},
{
"defaultBlockOrder" : "2",
"blockId" : "2",
"data" : "1120"
},
{
"defaultBlockOrder" : "3",
"blockId" : "3",
"data" : "1200"
}
],
"templateBlocks" : [
{
"blockId" : "1",
"label" : "Staffing Planner",
"quarter" : "",
"data" : "",
"dataType" : {
"typeId" : "1"
},
"tooltip" : {
"enable" : true,
"text" : ""
}
},
{
"blockId" : "2",
"label" : "Baseline",
"quarter" : "",
"data" : "",
"dataType" : {
"typeId" : "1"
},
"tooltip" : {
"enable" : true,
"text" : ""
}
},
{
"blockId" : "3",
"label" : "Projected",
"quarter" : "",
"data" : "",
"dataType" : {
"typeId" : "1"
},
"tooltip" : {
"enable" : true,
"text" : ""
}
}
]
}
Now I want to compare the two array of objects for each row, here in this case its "dataBlocks" and "templateBlocks" based on "blockId" s and I want to get the result in the following format.
{
"_id" : ObjectId("5a42432d69cbfed9a410e8ad"),
"bacId" : "BAC0023444",
"cardId" : "2",
"defaultCardOrder" : "2",
"alias" : "Finance",
"label" : "Finance",
"for" : "",
"cardTooltip" : {
"enable" : true,
"text" : ""
},
"blocks" : [
{
"defaultBlockOrder" : "1",
"blockId" : "1",
"data" : "0",
"label" : "Gross Profit",
"quarter" : "",
"dataType" : {
"typeId" : "2"
},
"tooltip" : {
"enable" : true,
"text" : ""
}
},
{
"defaultBlockOrder" : "2",
"blockId" : "2",
"data" : "0",
"label" : "Profit Forecast",
"quarter" : "",
"dataType" : {
"typeId" : "2"
},
"tooltip" : {
"enable" : true,
"text" : ""
}
},
{
"defaultBlockOrder" : "3",
"blockId" : "3",
"data" : "0",
"label" : "Resource Billing",
"quarter" : "",
"dataType" : {
"typeId" : "2"
},
"tooltip" : {
"enable" : true,
"text" : ""
}
}
]
},
{
"_id" : ObjectId("5a42432d69cbfed9a410e8ad"),
"bacId" : "BAC0023444",
"cardId" : "3",
"defaultCardOrder" : "3",
"alias" : "Staffing",
"label" : "Staffing",
"for" : "",
"cardTooltip" : {
"enable" : true,
"text" : ""
},
"dataBlocks" : [
{
"defaultBlockOrder" : "1",
"blockId" : "1",
"data" : "1212",
"label" : "Staffing Planner",
"quarter" : "",
"dataType" : {
"typeId" : "1"
},
"tooltip" : {
"enable" : true,
"text" : ""
}
},
{
"defaultBlockOrder" : "2",
"blockId" : "2",
"data" : "1120",
"label" : "Baseline",
"quarter" : "",
"dataType" : {
"typeId" : "1"
},
"tooltip" : {
"enable" : true,
"text" : ""
}
},
{
"defaultBlockOrder" : "3",
"blockId" : "3",
"data" : "1200",
"label" : "Projected",
"quarter" : "",
"dataType" : {
"typeId" : "1"
},
"tooltip" : {
"enable" : true,
"text" : ""
}
}
]
}
Is it possible to get it done with mongodb ? I am using 3.4 and trying to achieve this using aggregation.
Thanks in advance.
You can try below aggregation in 3.6.
The query below iterates the dataBlocks array and merges the data block element with template block element. The template block is looked up using $indexofArray which locates the array index with matching block id and $arrayElemAt to access the element at the found index.
db.collection_name.aggregate([{"$addFields":{
"blocks":{
"$map":{
"input":"$dataBlocks",
"in":{
"$mergeObjects":[
"$$this",
{"$arrayElemAt":[
"$templateBlocks",
{"$indexOfArray":["$templateBlocks.blockId","$$this.blockId"]}
]
}
]
}
}
}
}}])
For 3.4, replace $mergeObjects with combination of $arrayToObject, $objectToArray and $concatArrays to merge the each array element from both arrays.
db.collection_name.aggregate([{"$addFields":{
"blocks":{
"$map":{
"input":"$dataBlocks",
"in":{
"$arrayToObject":{
"$concatArrays":[
{"$objectToArray":"$$this"},
{"$objectToArray":{
"$arrayElemAt":[
"$templateBlocks",
{"$indexOfArray":["$templateBlocks.blockId","$$this.blockId"]
}
]
}}
]
}
}
}
}
}}])
You can use project with exclusion as last stage to remove array fields from output.
{"$project":{"templateBlocks":0,"dataBlocks":0}}
The following query does the job:
db.merge.aggregate([
// unwind twice
{$unwind: "$templateBlocks"},
{$unwind: "$dataBlocks"},
// get rid of documents where dataBlocks.blockId and
// templateBlocks.blockId are not equal
{$redact: {$cond: [{
$eq: [
"$dataBlocks.blockId",
"$templateBlocks.blockId"
]
},
"$$KEEP",
"$$PRUNE"
]
}
},
// merge dataBlocks and templateBlocks into a single document
{$project: {
bacId: 1,
cardId: 1,
defaultCardOrder: 1,
alias: 1,
label: 1,
for: 1,
cardTooltip: 1,
dataBlocks: {
defaultBlockOrder: "$dataBlocks.defaultBlockOrder",
blockId: "$dataBlocks.blockId",
data: "$dataBlocks.data",
label: "$templateBlocks.label",
quarter: "$templateBlocks.quarter",
data: "$templateBlocks.data",
dataType: "$templateBlocks.dataType",
tooltip: "$templateBlocks.tooltip"
}
}
},
// group to put correspondent dataBlocks to an array
{$group: {
_id: {
_id: "$_id",
bacId: "$bacId",
cardId: "$cardId",
defaultCardOrder: "$defaultCardOrder",
alias: "$alias",
label: "$label",
for: "$for",
cardTooltip: "$cardTooltip"
},
dataBlocks: {$push: "$dataBlocks" }
}
},
// remove the unnecessary _id object
{$project: {
_id: "$_id._id",
bacId: "$_id.bacId",
cardId: "$_id.cardId",
defaultCardOrder: "$_id.defaultCardOrder",
alias: "$_id.alias",
label: "$_id.label",
for: "$_id.for",
cardTooltip: "$_id.cardTooltip",
dataBlocks: "$dataBlocks"
}
}
])
Take into account that performance depends of size of your data set as the query unwinds twice and it may produce significant amount of intermediate documents.
Related
I'm new to mongodb and in this question I have 2 collections, one is selected_date, another is global_mobility_report, what I'm trying to do is to find entries in global_mobility_report whose date is in the selected_date so I use $lookup to join the two collections.
date_selected:
{
"_id" : ObjectId("5f60d81ba43174cf172ebfdc"),
"date" : ISODate("2020-05-22T00:00:00.000+08:00")
},
{
"_id" : ObjectId("5f60d81ba43174cf172ebfdd"),
"date" : ISODate("2020-05-23T00:00:00.000+08:00")
},
{
"_id" : ObjectId("5f60d81ba43174cf172ebfde"),
"date" : ISODate("2020-05-24T00:00:00.000+08:00")
},
{
"_id" : ObjectId("5f60d81ba43174cf172ebfdf"),
"date" : ISODate("2020-05-25T00:00:00.000+08:00")
},
{
"_id" : ObjectId("5f60d81ba43174cf172ebfe0"),
"date" : ISODate("2020-05-26T00:00:00.000+08:00")
},
{
"_id" : ObjectId("5f60d81ba43174cf172ebfe1"),
"date" : ISODate("2020-05-27T00:00:00.000+08:00")
}
global_mobility_report:
{
"_id" : ObjectId("5f49fb013acddb5eec37f99e"),
"country_region_code" : "AE",
"country_region" : "United Arab Emirates",
"sub_region_1" : "",
"sub_region_2" : "",
"metro_area" : "",
"iso_3166_2_code" : "",
"census_fips_code" : "",
"date" : "2020-02-15",
"retail_and_recreation_percent_change_from_baseline" : "0",
"grocery_and_pharmacy_percent_change_from_baseline" : "4",
"parks_percent_change_from_baseline" : "5",
"transit_stations_percent_change_from_baseline" : "0",
"workplaces_percent_change_from_baseline" : "2",
"residential_percent_change_from_baseline" : "1"
},
{
"_id" : ObjectId("5f49fb013acddb5eec37f99f"),
"country_region_code" : "AE",
"country_region" : "United Arab Emirates",
"sub_region_1" : "",
"sub_region_2" : "",
"metro_area" : "",
"iso_3166_2_code" : "",
"census_fips_code" : "",
"date" : "2020-02-16",
"retail_and_recreation_percent_change_from_baseline" : "1",
"grocery_and_pharmacy_percent_change_from_baseline" : "4",
"parks_percent_change_from_baseline" : "4",
"transit_stations_percent_change_from_baseline" : "1",
"workplaces_percent_change_from_baseline" : "2",
"residential_percent_change_from_baseline" : "1"
},
{
"_id" : ObjectId("5f49fb013acddb5eec37f9a0"),
"country_region_code" : "AE",
"country_region" : "United Arab Emirates",
"sub_region_1" : "",
"sub_region_2" : "",
"metro_area" : "",
"iso_3166_2_code" : "",
"census_fips_code" : "",
"date" : "2020-02-17",
"retail_and_recreation_percent_change_from_baseline" : "-1",
"grocery_and_pharmacy_percent_change_from_baseline" : "1",
"parks_percent_change_from_baseline" : "5",
"transit_stations_percent_change_from_baseline" : "1",
"workplaces_percent_change_from_baseline" : "2",
"residential_percent_change_from_baseline" : "1"
},
{
"_id" : ObjectId("5f49fb013acddb5eec37f9a1"),
"country_region_code" : "AE",
"country_region" : "United Arab Emirates",
"sub_region_1" : "",
"sub_region_2" : "",
"metro_area" : "",
"iso_3166_2_code" : "",
"census_fips_code" : "",
"date" : "2020-02-18",
"retail_and_recreation_percent_change_from_baseline" : "-2",
"grocery_and_pharmacy_percent_change_from_baseline" : "1",
"parks_percent_change_from_baseline" : "5",
"transit_stations_percent_change_from_baseline" : "0",
"workplaces_percent_change_from_baseline" : "2",
"residential_percent_change_from_baseline" : "1"
}
when I try to find all entries in global with 'date' match in selected_date(I have converted the string to data format in gobal_mobility_report), it returns empty array.
db.global_mobility_report.aggregate([
{$match:{country_region:"Indonesia"}},
{$addFields: {"dateconverted": {$convert: { input: "$date", to: "date", onError:"onErrorExpr", onNull:"onNullExpr"}:}}},
{
$lookup:
{
from: "selected_date",
localField:"dateconverted",
foreignField: "date",
as: "selected_dates" // empty
}
})]
The output is:
{
"_id" : ObjectId("5f49fd6a3acddb5eec4427bb"),
"country_region_code" : "ID",
"country_region" : "Indonesia",
"sub_region_1" : "",
"sub_region_2" : "",
"metro_area" : "",
"iso_3166_2_code" : "",
"census_fips_code" : "",
"date" : "2020-02-15",
"retail_and_recreation_percent_change_from_baseline" : "-2",
"grocery_and_pharmacy_percent_change_from_baseline" : "-2",
"parks_percent_change_from_baseline" : "-8",
"transit_stations_percent_change_from_baseline" : "1",
"workplaces_percent_change_from_baseline" : "5",
"residential_percent_change_from_baseline" : "1",
"dateconverted" : ISODate("2020-02-15T08:00:00.000+08:00"),
"selected_dates" : [ ]
},
{
"_id" : ObjectId("5f49fd6a3acddb5eec4427bc"),
"country_region_code" : "ID",
"country_region" : "Indonesia",
"sub_region_1" : "",
"sub_region_2" : "",
"metro_area" : "",
"iso_3166_2_code" : "",
"census_fips_code" : "",
"date" : "2020-02-16",
"retail_and_recreation_percent_change_from_baseline" : "-3",
"grocery_and_pharmacy_percent_change_from_baseline" : "-3",
"parks_percent_change_from_baseline" : "-7",
"transit_stations_percent_change_from_baseline" : "-4",
"workplaces_percent_change_from_baseline" : "2",
"residential_percent_change_from_baseline" : "2",
"dateconverted" : ISODate("2020-02-16T08:00:00.000+08:00"),
"selected_dates" : [ ]
}
The reason you are getting an empty array is because dateconverted does not match the date field.
The $lookup operator does an equality between the localField and the foreigntField field, so basically with an example
db.users.insertMany([
{ email: "test#example.com", userId: 0 },
{ email: "test2#example.com", userId: 1 },
{ email: "test3#example.com", userId: 2 },
{ email: "test3#example.com", userId: 3 }
]);
db.posts.insertMany([
{ by: 0, post: "hello world" },
{ by: 0 , post: "hello earthlings" },
{ by: 3, post: "test test test"}
]);
db.posts.aggregate([
{
$lookup: {
from: "users",
localField: "by",
foreignField: "userId",
as: "list_of_post"
}
}
]).toArray();
The output will be what it suppose to be, because the localField matched the ForeignField
[
{
"_id" : ObjectId("5f60f6859a6df3133b325eb0"),
"by" : 0,
"post" : "hello world",
"list_of_post" : [
{
"_id" : ObjectId("5f60f6849a6df3133b325eac"),
"email" : "test#example.com",
"userId" : 0
}
]
},
{
"_id" : ObjectId("5f60f6859a6df3133b325eb1"),
"by" : 0,
"post" : "hello earthlings",
"list_of_post" : [
{
"_id" : ObjectId("5f60f6849a6df3133b325eac"),
"email" : "test#example.com",
"userId" : 0
}
]
},
{
"_id" : ObjectId("5f60f6859a6df3133b325eb2"),
"by" : 3,
"post" : "test test test",
"list_of_post" : [
{
"_id" : ObjectId("5f60f6849a6df3133b325eaf"),
"email" : "test3#example.com",
"userId" : 3
}
]
}
]
Let's mimic a situation where it does not match
db.posts.drop();
db.posts.insertMany([
{ by: 20, post: "hello world" },
{ by: 23 , post: "hello earthlings" },
{ by: 50, post: "test test test"}
]);
We get an empty array
[
{
"_id" : ObjectId("5f60f83344304796ae700b4d"),
"by" : 20,
"post" : "hello world",
"list_of_post" : [ ]
},
{
"_id" : ObjectId("5f60f83344304796ae700b4e"),
"by" : 23,
"post" : "hello earthlings",
"list_of_post" : [ ]
},
{
"_id" : ObjectId("5f60f83344304796ae700b4f"),
"by" : 50,
"post" : "test test test",
"list_of_post" : [ ]
}
]
So, back to your question, the reason for the empty array is as a result of the dateconverted field not matching the date field. So, let's take a look at an example.
In the first document the dateconverted is
ISODate("2020-02-16T08:00:00.000+08:00") and checking at date_selected document , there is no field that correspond to this value ISODate("2020-02-16T08:00:00.000+08:00"). But let's manually insert this, so you will properly understand what I am talking about.
db.date_selected.insert({
"_id" : ObjectId(),
"date": ISODate("2020-02-16T08:00:00.000+08:00")
});
Running the aggregation pipeline will also make selected_dates an empty array. And the other thing you have to note is that the mm/dd/yyy part of the ISODate object does not also match any document in your question. Secondly, you have to devise another means of running the comparison, because the aggregation pipeline in the $addFileds stage will be affected by timezone and other issues as well.
I have this object as below.
{
"_id" : ObjectId("5ec80a981e89a84b19934039"),
"status" : "active",
"organizationId" : "1",
"productId" : "1947",
"name" : "BOOKEND & PAPER WEIGHT SET – ZODIAC PIG – RED COPPER + PLATINUM",
"description" : "This global exclusive Zodiac bookend and paperweight set from Zuny will stand auspiciously on your bookcase and table, spreading good luck and fortune throughout your home just in time for the Year of the Pig.",
"brand" : "ZUNY",
"created" : "2018-09-28 00:00:00",
"updated" : "2020-05-22 09:19:07",
"mainImage" : "https://",
"availableOnline" : true,
"colors" : [
{
"images" : [
{
"type" : "studio",
"url" : "https://"
},
{
"type" : "studio",
"url" : "https://"
},
{
"type" : "studio",
"url" : "https://"
}
],
"extraInfo" : [
{
"type" : "text-tag",
"title" : "CATEGORY",
"tags" : [
"HOME FURNISHING & DÉCOR",
"LIFESTYLE"
]
},
{
"type" : "text-tag",
"title" : "BRAND",
"tags" : [
"ZUNY"
]
},
{
"type" : "text-tag",
"title" : "COLOUR",
"tags" : [
"GOLD",
"ROSE GOLD"
]
},
{
"type" : "text-tag",
"title" : "SEASON",
"tags" : [
"AW(2018)"
]
},
{
"type" : "text-tag",
"title" : "HASHTAG",
"tags" : [
"BOOKCASES",
"BOOKEND",
"COLOUR",
"EXCLUSIVE",
"GLOBAL EXCLUSIVE",
"HOME",
"LEATHER",
"MOTIF",
"OBJECTS",
"PAPER",
"PAPERWEIGHT",
"PLATINUM",
"SET",
"SYNTHETIC",
"ZODIAC",
"HANDMADE",
"time"
]
}
],
"_id" : ObjectId("5ec80a981e89a84b1993403a"),
"colorId" : "1",
"color" : "ROSE GOLD",
"status" : "active",
"sizes" : [
{
"extraInfo" : [
{
"type" : "text-block",
"title" : "Size And Fit",
"text" : ""
},
{
"type" : "text-block",
"title" : "Information",
"text" : "Global exclusive. Colour: Copper/Platinum. Set includes: Zodiac Pig bookend (x 1), Zodiac Pig paperweight (x 1). Metallic copper- and platinum-tone synthetic leather. Pig motif. Iron pellet filling. Handmade"
}
],
"_id" : ObjectId("5ec80a981e89a84b1993403b"),
"sizeId" : "1",
"neo" : "0210111790664",
"size" : "*",
"originalPrice" : "1060.00",
"sellingPrice" : "1060.00",
"discountPercent" : "0.00",
"url" : "https://",
"status" : "active",
"currency" : "HK$",
"stores" : [
{
"storeId" : "1",
"quantity" : 70,
"_id" : ObjectId("5ec80a981e89a84b1993403c"),
"available" : 70,
"reserved" : 0,
"name" : "Park Street",
"status" : "active"
},
{
"storeId" : "2",
"quantity" : 95,
"_id" : ObjectId("5ec80a981e89a84b1993403d"),
"name" : "Rashbehari",
"status" : "active"
}
]
}
]
}
],
"__v" : 0
}
I want the output as follows
{
"name": "Mock Collection",
"collectionId": "92",
"products": [
{
"title": "GLOBAL EXCLUSIVE OFF-SHOULDER SHIRT DRESS",
"imageUrl": "https://",
"productId": "21174",
"currency": "" // This should be this.colors[0].sizes[0].currency
},
]
}
How to get the nested field. I tried using arrayElemAt by which I was able to get to colors[0]. But I am confused how to get inside the nested object of sizes from there. Also the currency node should have the exact value. It comes like currency:{currency: value} which I don't want.
Please help!
Not sure how you've got that output but to extract currency from first object of sizes then you need to try this :
db.collection.aggregate([
{
$project: {
currency: {
$arrayElemAt: [
{
$arrayElemAt: [ "$colors.sizes.currency", 0 ] // gives an array of currency values, in your case since you've only one object just an array of one value
},
0
]
}
}
}
])
Test : mongoplayground
Here I have updated my question.
This is the input data, you can use this command to insert in your local db:
db.pms_teamleadtimesheets.insertMany( [
{ "Text" : "Analysis",
"Comments" : "4",
"TaskType" : "DELIVERY",
"Items" : "Others",
"StartDate" : "28-05-2018",
"EndDate" : "2018-05-28",
"Hours" : 240,
"phase" : "Analysis",
"ProjectID" : "5a042ba02af18ac8388bd3c0",
"UserName" : "Admin",
"FacilityID" : "59a53f0c6077b2a029c52b7f",
"TaskID" : "5b0baafffb8df2401af90fea",
"TaskDescription" : "Analysis",
"IsBillable" : true
},
{ "Text" : "Analysis",
"Comments" : "8",
"TaskType" : "DELIVERY",
"Items" : "Others",
"StartDate" : "28-05-2018",
"EndDate" : "2018-05-28",
"Hours" : 240,
"phase" : "Analysis",
"ProjectID" : "5a042ba02af18ac8388bd3c0",
"UserName" : "Admin",
"FacilityID" : "59a53f0c6077b2a029c52b7f",
"TaskID" : "5b0baafffb8df2401af90fea",
"TaskDescription" : "Analysis",
"IsBillable" : true
},
{"Text" : "Analysis",
"Comments" : "2",
"TaskType" : "DELIVERY",
"Items" : "CRI",
"StartDate" : "29-05-2018",
"EndDate" : "2018-05-29",
"Hours" : 120,
"phase" : "Analysis",
"ProjectID" : "5a042ba02af18ac8388bd3c0",
"UserName" : "Admin",
"FacilityID" : "59a53f0c6077b2a029c52b7f",
"TaskID" : "5b0baafffb8df2401af90fea",
"TaskDescription" : "Analysis",
"IsBillable" : true
},
{ "Text" : "Analysis",
"Comments" : "2",
"TaskType" : "DELIVERY",
"Items" : "CRI",
"StartDate" : "29-05-2018",
"EndDate" : "2018-05-29",
"Hours" : 120,
"phase" : "Analysis",
"ProjectID" : "5a042ba02af18ac8388bd3c0",
"UserName" : "Admin",
"FacilityID" : "59a53f0c6077b2a029c52b7f",
"TaskID" : "5b0baafffb8df2401af90fea",
"TaskDescription" : "Analysis",
"IsBillable" : true }
] );
From this collection, I want to do distinct and sum. Here distinct is working fine but the sum is not working.
this is the query I have used:
db.Collection.aggregate([
//where query
{ "$match": { UserName: "USER",FacilityID:"FID",ProjectID:"ID" } },
//distinct column
{ "$group": { _id: { ProjectID: "$ProjectID", Task: "$Text", Phase: "$phase", Comments: "$Comments", TaskType: "$TaskType", Items: "$Items", UserName: "$UserName", IsBillable: "$IsBillable", Date: "$StartDate", Hours:{$sum:"$Hours" } }} },
//provide column name for the output
{ "$project": { _id: 0, ProjectID: "$_id.ProjectID" ,Phase: "$_id.Phase",Task: "$_id.Task",Comments: "$_id.Comments",TaskType: "$_id.TaskType",Items: "$_id.Items",UserName: "$_id.UserName",IsBillable: "$_id.IsBillable",Date: "$_id.Date",Hours: { $divide: [ "$_id.Hours", 60 ] } } }
]);
I am getting the result like this. It does not calculating the sum of the value.
Total hours is not getting added here. It should return 4 but here it is returning 2.
can anyone resolve me to solve this?
The $group stage has the following prototype form:
{ $group: { _id: <expression>, <field1>: { <accumulator1> : <expression1> }, ... } }
Your field1 is Hours and accumulator1 is sum,
Therefore your aggregation should be like this:
db.pms_teamleadtimesheets.aggregate(
// Pipeline
[
// Stage 1
{
$match: {
UserName:"Admin",
FacilityID:"59a53f0c6077b2a029c52b7f",
ProjectID:"5a042ba02af18ac8388bd3c0"
}
},
// Stage 2
{
$group: {
_id: { ProjectID: "$ProjectID",
Task: "$Text", Phase: "$phase",
Comments: "$Comments",
TaskType: "$TaskType",
Items: "$Items",
UserName: "$UserName",
IsBillable: "$IsBillable",
Date: "$StartDate"
},
Hours:{$sum:"$Hours" }
}
},
// Stage 3
{
$project: {
_id: 0,
ProjectID: "$_id.ProjectID",
Phase: "$_id.Phase",
Task: "$_id.Task",
Comments: "$_id.Comments",
TaskType: "$_id.TaskType",
Items: "$_id.Items",
UserName: "$_id.UserName",
IsBillable: "$_id.IsBillable",
Date: "$_id.Date",
Hours: {
$divide: [ "$Hours", 60 ]
}
}
},
]
);
Output for with the given test data:
{
"ProjectID" : "5a042ba02af18ac8388bd3c0",
"Phase" : "Analysis",
"Task" : "Analysis",
"Comments" : "2",
"TaskType" : "DELIVERY",
"Items" : "CRI",
"UserName" : "Admin",
"IsBillable" : true,
"Date" : "29-05-2018",
"Hours" : 4.0
}
{
"ProjectID" : "5a042ba02af18ac8388bd3c0",
"Phase" : "Analysis",
"Task" : "Analysis",
"Comments" : "8",
"TaskType" : "DELIVERY",
"Items" : "Others",
"UserName" : "Admin",
"IsBillable" : true,
"Date" : "28-05-2018",
"Hours" : 4.0
}
{
"ProjectID" : "5a042ba02af18ac8388bd3c0",
"Phase" : "Analysis",
"Task" : "Analysis",
"Comments" : "4",
"TaskType" : "DELIVERY",
"Items" : "Others",
"UserName" : "Admin",
"IsBillable" : true,
"Date" : "28-05-2018",
"Hours" : 4.0
}
Further read here
I am attempting to seed a database with a json array of data with mongoimport, however when the data reaches the mongo collection, it imports as a key in the collection object like this:
"items" is my json file, it always shows up as "items", I want the parent array to be the array I'm trying to import itself, does this make sense?
Update
Please see this example, the first image is how mongoimport is importing this array of objects:
{ "_id" : ObjectId("58dc01ecec116d4c9039e47c"), "items" : [ { "id" : 1, "_id" : "item1", "type" : "alert", "title" : "hello.world", "email" : "something#something.com", "message" : "", "createdDate" : "date", "price" : "$9.00", "active" : true }, { "id" : 2, "_id" : "item2", "type" : "welcome.lol", "title" : "Item 2", "email" : "something#something.com", "message" : "lol", "createdDate" : "date", "price" : "$12.00", "active" : true }, { "id" : 3, "_id" : "item3", "type" : "message", "title" : "various.domain", "email" : "something#something.com", "message" : "lol", "createdDate" : "date", "price" : "$3.00", "active" : false }, { "id" : 4, "_id" : "item4", "type" : "message", "title" : "something.else", "message" : "", "createdDate" : "date", "price" : "$12.00", "active" : false }, { "id" : 5, "_id" : "item5", "type" : "update", "title" : "wow.lol", "email" : "something#something.com", "message" : "", "createdDate" : "date", "price" : "$12.00", "active" : false }, { "id" : 6, "_id" : "item6", "type" : "update", "title" : "domainname.net", "email" : "something#something.com", "message" : "cars", "createdDate" : "date", "price" : "$12.00", "active" : false }, { "id" : 7, "_id" : "item7", "type" : "update", "title" : "something.lol", "email" : "something#something.com", "message" : "", "createdDate" : "date", "price" : "$12.00", "active" : false } ] }
Notice how its treats the entire array as an "item" object, with a key in the item "items" which is the array, I want the data to look like this:
{ "_id" : ObjectId("58dc027a2c74df002a957281"), "price" : "asdf", "message" : "asdf", "email" : "aasfd", "title" : "asdf", "dateCreated" : ISODate("2017-03-29T18:52:42.227Z"), "active" : true, "__v" : 0 }
{ "_id" : ObjectId("58dc027b2c74df002a957282"), "price" : "asdf", "message" : "asdf", "email" : "aasfd", "title" : "asdf", "dateCreated" : ISODate("2017-03-29T18:52:43.574Z"), "active" : true, "__v" : 0 }
{ "_id" : ObjectId("58dc027b2c74df002a957283"), "price" : "asdf", "message" : "asdf", "email" : "aasfd", "title" : "asdf", "dateCreated" : ISODate("2017-03-29T18:52:43.708Z"), "active" : true, "__v" : 0 }
{ "_id" : ObjectId("58dc027b2c74df002a957284"), "price" : "asdf", "message" : "asdf", "email" : "aasfd", "title" : "asdf", "dateCreated" : ISODate("2017-03-29T18:52:43.855Z"), "active" : true, "__v" : 0 }
{ "_id" : ObjectId("58dc027b2c74df002a957285"), "price" : "asdf", "message" : "asdf", "email" : "aasfd", "title" : "asdf", "dateCreated" : ISODate("2017-03-29T18:52:43.994Z"), "active" : true, "__v" : 0 }
{ "_id" : ObjectId("58dc027c2c74df002a957286"), "price" : "asdf", "message" : "asdf", "email" : "aasfd", "title" : "asdf", "dateCreated" : ISODate("2017-03-29T18:52:44.128Z"), "active" : true, "__v" : 0 }
{ "_id" : ObjectId("58dc027c2c74df002a957287"), "price" : "asdf", "message" : "asdf", "email" : "aasfd", "title" : "asdf", "dateCreated" : ISODate("2017-03-29T18:52:44.263Z"), "active" : true, "__v" : 0 }
{ "_id" : ObjectId("58dc027c2c74df002a957288"), "price" : "asdf", "message" : "asdf", "email" : "aasfd", "title" : "asdf", "dateCreated" : ISODate("2017-03-29T18:52:44.391Z"), "active" : true, "__v" : 0 }
Where each item in the array is created as an "item" in mongo, each with its own ObjectID - otherwise it's useless for CRUD applications.
Docker MongoDB Log:
mongodb_1 | 2017-03-29T21:38:09.439+0000 I COMMAND [conn1] command reach-engine.domains command: insert { insert: "domains", documents: [ { items: [ { id: 1, _id: "item1", type: "alert", title: "hello.world", email: "something#something.com", message: "", createdDate: "date", price: "$9.00", active: true }, { id: 2, _id: "item2", type: "welcome.lol", title: "Item 2", email: "something#something.com", message: "lol", createdDate: "date", price: "$12.00", active: true }, { id: 3, _id: "item3", type: "message", title: "various.domain", email: "something#something.com", message: "lol", createdDate: "date", price: "$3.00", active: false }, { id: 4, _id: "item4", type: "message", title: "something.else", message: "", createdDate: "date", price: "$12.00", active: false }, { id: 5, _id: "item5", type: "update", title: "wow.lol", email: "something#something.com", message: "", createdDate: "date", price: "$12.00", active: false }, { id: 6, _id: "item6", type: "update", title: "domainname.net", email: "something#something.com", message: "cars", createdDate: "date", price: "$12.00", active: false }, { id: 7, _id: "item7", type: "update", title: "something.lol", email: "something#something.com", message: "", createdDate: "date", price: "$12.00", active: false } ] } ], writeConcern: { getLastError: 1, w: 1 }, ordered: false } ninserted:1 keyUpdates:0 writeConflicts:0 numYields:0 reslen:40 locks:{ Global: { acquireCount: { r: 2, w: 2 } }, Database: { acquireCount: { w: 1, W: 1 } }, Collection: { acquireCount: { W: 1 } } } protocol:op_query 250ms
It would be useful to know what command you are using to import, but I just created a database an imported the following JSON with this command:
mongoimport --db test --collection example --type json --file example.json --jsonArray
Make sure you are using the --jsonArray flag
example.json
[
{
"color": "red",
"value": "#f00"
},
{
"color": "green",
"value": "#0f0"
},
{
"color": "blue",
"value": "#00f"
},
{
"color": "cyan",
"value": "#0ff"
},
{
"color": "magenta",
"value": "#f0f"
},
{
"color": "yellow",
"value": "#ff0"
},
{
"color": "black",
"value": "#000"
}
]
I am trying to delete a section of sub documents from a collections..
Tried (and many others):
db.collection.remove( {'Segments': {$gte: '20150612141038' }} )
db.collection.remove( { 'Segments.$' : {$gte: '0150612141038' }} )
db.collection.deleteMany( { 'Segments.$' : {$gte: '0150612141038' }} )
db.collection.deleteOne( { 'Segments.$' : {$eq: '0150612141038' }} )
just can't figure out what I am doing wrong...
{
"_id" : ObjectId("56e32c5147e030bc0a000035"),
"Date" : "2015-06-12",
"UnitID" : "5",
"Segments" : {
"20150612141037" : {
"Parameters" : {
"647" : "0",
"649" : "16",
"653" : "0",
"655" : "0",
"656" : "0",
"658" : "98",
"664" : "447.0486",
"666" : "442.7083",
"677" : "122.8004",
}
},
"20150612141038" : {
"Parameters" : {
"658" : "96",
"664" : "451.3889",
"666" : "447.0486",
"677" : "122.7892"
}
},
"20150612141039" : {
"Parameters" : {
"658" : "44",
"664" : "442.7083",
"677" : "122.8004",
"704" : "1"
}
},
First of all I think your queries are wrong.
If you try this query to the mongoShell:
db.bios.find({'Segments': {$gte: '20150612141038'}})
you don't have anything as output because 20150612141038 is a document and not a field. Maybe you can reshape your schema to set 20150612141038 as a field and Segments as an array of documents:
{
"_id" : ObjectId("56e32c5147e030bc0a000035"),
"Date" : "2015-06-12",
"UnitID" : "5",
"Segments" : [
{
"segmentId" : "20150612141037",
"Parameters" : {
"647" : "0",
"649" : "16",
"653" : "0",
"655" : "0",
"656" : "0",
"658" : "98",
"664" : "447.0486",
"666" : "442.7083",
"677" : "122.8004"
}
},
{
"segmentId" : "20150612141038",
"Parameters" : {
"658" : "96",
"664" : "451.3889",
"666" : "447.0486",
"677" : "122.7892"
}
},
{
"segmentId" : "20150612141039",
"Parameters" : {
"658" : "44",
"664" : "442.7083",
"677" : "122.8004",
"704" : "1"
}
}
]
}
and then you can use $pull operator to remove documents from Segments array where the field Segments.segmentId has a certain value:
db.collection.update({},
{$pull:{Segments:{"segmentId":{$eq:"20150612141039"}}}},
{ multi: true}
)