MongoDB - query in denormalized model - mongodb

I have to show the advantages to use normalized model(in this case), with two collections in MongoDB: the first for coaches and the second for teams.
So, I use a denormalized model to show the differences.
For example, if I want to update the palmarès of Barcellona(from 23 Liga to 24 Liga), with denormalized model, I have to find all coaches that coached Barcellona and then I have to update the palmarès inside each coach. Clearly it's too expensive. I want to do this example.
I have this denormalized model of soccer coaches and teams they have coached.
Here is an example:
"_id" : "LEMG_1970",
"name" : "Luis",
"surname" : "Enrique Martinez Garcia",
"age" : 45,
"date_Of_birth" : {
"day" : 8,
"month" : 5,
"year" : 1970
},
"place_Of_birth" : "Gijòn",
"nationality" : "Spanish",
"preferred_formation" : "4-3-3 off",
"coached_Team" : [
{
"_id" : "Bar.43",
"official_name" : "Futbol Club Barcelona"
"common_name" : "Barcellona",
"country" : "Spain",
"started_by" : {
"day" : 28,
"month" : 11,
"year" : 1899
},
"championship" : "La Liga",
"stadium" : {
"name" : "Camp Nou",
"capacity" : 99354
},
"palmarès" : {
"La Liga" : 23,
"Copa del Rey" : 27,
"Supercopa de Espana" : 11,
"UEFA Champions League" : 4,
"UEFA Cup Winners Cup" : 4,
"UEFA Super Cup" : 4,
"FIFA Club World cup" : 2
},
"average age" : 26.9,
"squad value(in mln)" : 591.5,
"foreigners" : 13,
"uniform" : [
"blue",
"dark red"
],
"in_charge" : {
"from" : {
"day" : 1,
"month" : 7,
"year" : 2014
}
},
"matches" : 59
},
{
{
"_id" : "Rom.01",
"official_name" : "Associazione Sportiva Roma SpA",
"common_name" : "Roma",
"country" : "Italy",
"started_by" : {
"day" : 22,
"month" : 6,
"year" : 1927
},
"championship" : "Serie A",
"stadium" : {
"name" : "Olimpico di Roma",
"capacity" : 73261
},
"palmarès" : {
"Serie A" : 3,
"Coppa Italia" : 9,
"Supercoppa Italiana" : 2,
"Serie B" : 1
},
"average age" : 28.3,
"squad value(in mln)" : 253.7,
"foreigners" : 22,
"uniform" : [
"red",
"yellow"
],
"in_charge" : {
"from" : {
"day" : 7,
"month" : 6,
"year" : 2011
},
"to" : {
"day" : 10,
"month" : 5,
"year" : 2012
}
},
"matches" : 41
}
]
As you can see information about teams are into coach document. Now, I want to update the palmarès of Barcellona. I tried this query, but I got an error:
db.coach.update({_id:"LEMG_1970"}, {$set:{"coached_Team.palmarès.La Liga":24}})
This is the advice:
"code" : 16837,
"errmsg" : "cannot use the part (coached_Team of coached_Team.palmarès.La Liga) to traverse the element
What can I do to update the palmarès with denormalized model?

Use the $ positional operator in your update, this identifies an element in an array to update without explicitly specifying the position of the element in the array. Since the positional $ operator acts as a placeholder for the first element that matches the query document, the the array field must appear as part of the query document hence you need the coached_Team array field in your query:
var query = {
"_id" : "LEMG_1970",
"coached_Team._id" : "Bar.43"
},
update = {
"$set": {
"coached_Team.$.palmarès.La Liga": 24
}
};
db.coach.update(query, update);

Related

Get value by key in Array Object to Array in mongodb & mongoose by query

I have a question about mongodb.
I have a collection with documents:
{
"_id" : ObjectId("5b5445b44ae5aa0c0c625378"),
"skills" : [
{
"skillId" : 11,
"level" : 10,
"available" : 1,
"_id" : ObjectId("5b5445b44ae5aa0c0c62537c")
},
{
"skillId" : 12,
"level" : 10,
"available" : 1,
"_id" : ObjectId("5b5445b44ae5aa0c0c62537b")
},
{
"skillId" : 13,
"level" : 1,
"available" : 0,
"_id" : ObjectId("5b5445b44ae5aa0c0c62537a")
},
{
"skillId" : 14,
"level" : 1,
"available" : 0,
"_id" : ObjectId("5b5445b44ae5aa0c0c625379")
}
]
}
Now, I want to select all skill -> level in this document to an array in new object with current id
Ex :
{
"_id" : ObjectId("5b5445b44ae5aa0c0c625378"),
"skills": [10, 10,1,1]
}
Result is same as aggregate query [{$project:{ "skills": "$skills.level" }}]
but aggregate is not recommended in this case!
Can you tell me how I using find in Mongoose to do that?

Aggregate distinct values in MongoDB

I have a mongodb db with 18625 collections. It has following keys:
"_id" : ObjectId("5aab14d2fc08b46adb79d99c"),
"game_id" : NumberInt(4),
"score_phrase" : "Great",
"title" : "NHL 13",
"url" : "/games/nhl-13/ps3-128181",
"platform" : "PlayStation 3",
"score" : 8.5,
"genre" : "Sports",
"editors_choice" : "N",
"release_year" : NumberInt(2012),
"release_month" : NumberInt(9),
"release_day" : NumberInt(11)
Now, i wish to create another dimension/ collection with only genres.
If i use the following query :
db.ign.aggregate([ {$project: {"genre":1}}, { $out: "dimen_genre" } ]);
It generates 18625 collections, even though there are only 113 distinct
genres.
How to apply distinct here and get the collection for genres with only the distinct 113 values.
I googled, bt it showed that aggregate and distinct don't work together in mongo.
I also tried : db.dimen_genre.distinct('genre').length
this showed that in dimension_genre, there are 113 distinct genres.
Precisely,
how to make a collection from existing one with only distinct values.
I am really new to NoSQLs.
You can use $addToSet to group unique values in one document and then $unwind to get back multiple docs:
db.ign.aggregate([
{
$group: {
_id: null,
genre: { $addToSet: "$genre" }
}
},
{
$unwind: "$genre"
},
{
$project: {
_id: 0
}
},
{ $out: "dimen_genre" }
]);
You can try
db.names.aggregate(
[
{ $group : { _id : "$genre", books: { $push: "$$ROOT" } } }
]
)
I have tried with Test and Sports as genre
It gives you output something like this
{
"_id" : "Test",
"books" : [
{
"_id" : ObjectId("5aaea6150cc1403ee9a02e0c"),
"game_id" : 4,
"score_phrase" : "Great",
"title" : "NHL 13",
"url" : "/games/nhl-13/ps3-128181",
"platform" : "PlayStation 3",
"score" : 8.5,
"genre" : "Test",
"editors_choice" : "N",
"release_year" : 2012,
"release_month" : 9,
"release_day" : 11
}
]
}
/* 2 */
{
"_id" : "Sports",
"books" : [
{
"_id" : ObjectId("5aaea3be0cc1403ee9a02d97"),
"game_id" : 4,
"score_phrase" : "Great",
"title" : "NHL 13",
"url" : "/games/nhl-13/ps3-128181",
"platform" : "PlayStation 3",
"score" : 8.5,
"genre" : "Sports",
"editors_choice" : "N",
"release_year" : 2012,
"release_month" : 9,
"release_day" : 11
},
{
"_id" : ObjectId("5aaea3c80cc1403ee9a02d9b"),
"game_id" : 4,
"score_phrase" : "Great",
"title" : "NHL 13",
"url" : "/games/nhl-13/ps3-128181",
"platform" : "PlayStation 3",
"score" : 8.5,
"genre" : "Sports",
"editors_choice" : "N",
"release_year" : 2012,
"release_month" : 9,
"release_day" : 11
},
{
"_id" : ObjectId("5aaea3cf0cc1403ee9a02d9f"),
"game_id" : 4,
"score_phrase" : "Great",
"title" : "NHL 13",
"url" : "/games/nhl-13/ps3-128181",
"platform" : "PlayStation 3",
"score" : 8.5,
"genre" : "Sports",
"editors_choice" : "N",
"release_year" : 2012,
"release_month" : 9,
"release_day" : 11
}
]
}

Retrieving Data in MongoDB

{
"ID" : 7,
"vendor" : "Gold's Gym",
"savings" : 50,
"value" : 300,
"description" : "Get a 3 month membership for $250 ($300 value)",
"terms" : "Non transferrable",
"product" : "Membership",
"expires" : {
"year" : 2017,
"month" : 7,
"date" : 31
},
"code" : "GYM-1",
"tags" : [
"fitness"
]
},
{
"ID" : 8,
"vendor" : "Golds Gym",
"discount" : 15,
"description" : "Get 15% discount on fitness classes",
"terms" : "Non transferrable",
"exceptions" : "Not applicable to swimming classes",
"product" : "Classes",
"purchaseValidity" : {
"year" : 2017,
"month" : 7,
"date" : 31
},
"expires": {
"year" : 2017,
"month" : 12,
"date" : 31
},
"code" : "GYM-2",
"tags" : [
"fitness"
]
}
This is part of a lager code. However, I want to retrieve the data items with tag: fitness that offer discounts: $gte 10 or savings above 10
This is what I started working with, however I cant find the syntax to work with both discounts and fitness
items.find({tags: "fitness"}, {discount: {$gte: 10}}).pretty()
You Can Do it like this :-
1.$elemMatch used for match in arrays.
2.$and in by Default in query.
items.find({ tags:{ $elemMatch:{$eq: "fitness"}} ,
$or:[ {discount: {$gte: 10}},
{savings: {$gte: 10}}
] })
Thanks.

Aggregate based on Array value

I have collection schema like :
{
"_id" : ObjectId("582ee289618a504e5c830e03"),
"updatedAt" : ISODate("2016-11-24T05:01:59.470Z"),
"createdAt" : ISODate("2016-11-18T11:14:17.912Z"),
"requestId" : "IER5R2H",
"pickupDetails" : {
"_id" : ObjectId("58367447b0a1ada74ad7af7e"),
"itemsCount" : 1,
"pickupItems" : [
{
"name" : "Newspaper",
"quantity" : 15,
"unit" : "kg",
"unitPrice" : 9,
"amount" : 135,
"_id" : ObjectId("58367447b0a1ada74ad7af7f")
}
]
}}
{
"_id" : ObjectId("58fff31a618a504e5c831191"),
"updatedAt" : ISODate("2016-11-21T13:37:51.267Z"),
"createdAt" : ISODate("2016-11-19T06:37:14.857Z"),
"requestId" : "M7OZY9O",
"pickupDetails" : {
"_id" : ObjectId("5832f8afb8ec77fa3c518f97"),
"itemsCount" : 2,
"pickupItems" : [
{
"name" : "Newspaper",
"quantity" : 18,
"unit" : "kg",
"unitPrice" : 11,
"amount" : 198,
"_id" : ObjectId("5832f8afb8ec77fa3c518f98")
},
{
"name" : "Plastic",
"quantity" : 4,
"unit" : "kg",
"unitPrice" : 11,
"amount" : 44,
"_id" : ObjectId("584a853e46c71be3585bfb5a")
}
]
}}
I need to add the quantity based on the name of pickupItems, like "Newspaper" etc. Suppose quantity of Newspaper for a particular day.
As per the below data, result should be like, {"Newspaper":33}, for a particular date.
try this :
db.collection.aggregate([
{
$unwind:"$pickupDetails.pickupItems"
},
{
$group:{
_id:"$pickupDetails.pickupItems.name",
quantity:{
$sum:"$pickupDetails.pickupItems.quantity"
}
}
}
])
output:
{ "_id" : "Plastic", "quantity" : 4 }
{ "_id" : "Newspaper", "quantity" : 33 }
you can add a $match stage at the begining of the pipeline to get results for a particular day

Moongo db aggregation in embeded document

i'am working on aggregating some data from mongodb et here is an exemple document from my collection :
{
"_id" : ObjectId("573dd055f32d05411462894e"),
"metadata" : {
"ip" : "105.12.84.26",
"yearmonthday" : "20160519",
"hour" : 14,
"month" : 5,
"day" : 19,
"yearmonth" : "201605",
"minute" : 41,
"year" : 2016
},
"new" : {
"minutes" : {
"40" : 1
},
"hourly" : {
"14" : 1
}
},
"minute" : {
"14" : {
"40" : 3,
"41" : 7
}
},
"hourly" : {
"14" : 10
}
}
this collection is recolting the ip address then store then, new is thehour et minute an ip address request the site for the firste time.
I want my result to respond to this : in an interval of time (between hour "X" and hour "Y"), how much the same ip adress connected to my site ?
can onyone help ? thx
Finally, i changed my data model to a simpler one like this :
{
"_id" : ObjectId("573ee726f32d054114648cdb"),
"day" : 20,
"minute" : 29,
"ip" : "197.48.5.8",
"yearmonthday" : "20160520",
"hour" : 10,
"month" : 5,
"year" : 2016
}
{
"_id" : ObjectId("573ee72cf32d054114648cff"),
"day" : 20,
"minute" : 30,
"ip" : "197.48.5.8",
"yearmonthday" : "20160520",
"hour" : 10,
"month" : 5,
"year" : 2016
}
so that a can easily aggregate ip connection based on time range.