elemMatch doesn't retrieve data from [ ] brackets in MongoDB - mongodb

Structure of collection:
{
"address": {
"building": "1007",
"coord": [ -73.856077, 40.848447 ],
"street": "Morris Park Ave",
"zipcode": "10462"
},
"borough": "Bronx",
"cuisine": "Bakery",
"grades": [
{ "date": { "$date": 1393804800000 }, "grade": "A", "score": 2 },
{ "date": { "$date": 1378857600000 }, "grade": "A", "score": 6 },
{ "date": { "$date": 1358985600000 }, "grade": "A", "score": 10 },
{ "date": { "$date": 1322006400000 }, "grade": "A", "score": 9 },
{ "date": { "$date": 1299715200000 }, "grade": "B", "score": 14 }
],
"name": "Morris Park Bake Shop",
"restaurant_id": "30075445"
}
The first query below doesn't return any results, second does. Why?
"coord": [ -73.856077, 40.848447 ] Here coord is an array of two elements so why isn't elemMatch returning anything?
> db.restaurants.find({address : { $elemMatch: { coord: {$lt : -95.754168}}}});
>
>
> db.restaurants.find({"address.coord" : {$lt : -95.754168}});
{ "_id" : ObjectId("5ed53c72c7494f71176bafb9"), "address" : { "building" : "3707", "coord" : [ -101.8945214, 33.5197474 ], "street" : "82 Street", "zipcode" : "11372" }, "borough" : "Queens", "cuisine" : "American ", "grades" : [ { "date" : ISODate("2014-06-04T00:00:00Z"), "grade" : "A", "score" : 12 }, { "date" : ISODate("2013-11-07T00:00:00Z"), "grade" : "B", "score" : 19 }, { "date" : ISODate("2013-05-17T00:00:00Z"), "grade" : "A", "score" : 11 }, { "date" : ISODate("2012-08-29T00:00:00Z"), "grade" : "A", "score" : 11 }, { "date" : ISODate("2012-04-03T00:00:00Z"), "grade" : "A", "score" : 12 }, { "date" : ISODate("2011-11-16T00:00:00Z"), "grade" : "A", "score" : 7 } ], "name" : "Burger King", "restaurant_id" : "40534067" }
{ "_id" : ObjectId("5ed53c72c7494f71176bb325"), "address" : { "building" : "15259", "coord" : [ -119.6368672, 36.2504996 ], "street" : "10 Avenue", "zipcode" : "11357" }, "borough" : "Queens", "cuisine" : "Italian", "grades" : [ { "date" : ISODate("2014-09-04T00:00:00Z"), "grade" : "A", "score" : 11 }, { "date" : ISODate("2014-03-26T00:00:00Z"), "grade" : "A", "score" : 8 }, { "date" : ISODate("2013-03-04T00:00:00Z"), "grade" : "A", "score" : 10 }, { "date" : ISODate("2012-09-27T00:00:00Z"), "grade" : "A", "score" : 10 }, { "date" : ISODate("2012-04-20T00:00:00Z"), "grade" : "A", "score" : 7 }, { "date" : ISODate("2011-11-23T00:00:00Z"), "grade" : "C", "score" : 34 } ], "name" : "Cascarino'S", "restaurant_id" : "40668681" }
{ "_id" : ObjectId("5ed53c72c7494f71176bb7c8"), "address" : { "building" : "60", "coord" : [ -111.9975205, 42.0970258 ], "street" : "West Side Highway", "zipcode" : "10006" }, "borough" : "Manhattan", "cuisine" : "Japanese", "grades" : [ { "date" : ISODate("2014-03-20T00:00:00Z"), "grade" : "A", "score" : 9 }, { "date" : ISODate("2013-06-28T00:00:00Z"), "grade" : "A", "score" : 11 }, { "date" : ISODate("2012-07-05T00:00:00Z"), "grade" : "A", "score" : 13 }, { "date" : ISODate("2011-07-27T00:00:00Z"), "grade" : "A", "score" : 2 } ], "name" : "Sports Center At Chelsea Piers (Sushi Bar)", "restaurant_id" : "40882356" }

The reason:
Your array doesn't contain valid element.
Smallest value in negative is the greatest value. So -73 is > than -95 and 40 is > -95.
Play
And other works. play
Both formats are valid. But data(mentioned coord) is also not matching the query in both the formats.

It is not finding the records because the schema would be different when translated.
For example: if you change your schema to the following, it will return the document:
{
"address": [{
"building": "1007",
"coord": [ -73.856077, 40.848447 ],
"street": "Morris Park Ave",
"zipcode": "10462"
}],
"borough": "Bronx",
"cuisine": "Bakery",
"grades": [
{ "date": { "$date": 1393804800000 }, "grade": "A", "score": 2 },
{ "date": { "$date": 1378857600000 }, "grade": "A", "score": 6 },
{ "date": { "$date": 1358985600000 }, "grade": "A", "score": 10 },
{ "date": { "$date": 1322006400000 }, "grade": "A", "score": 9 },
{ "date": { "$date": 1299715200000 }, "grade": "B", "score": 14 }
],
"name": "Morris Park Bake Shop",
"restaurant_id": "30075445"
}
Notice the square brackets around address sub-document.
Please follow this link for more reference https://docs.mongodb.com/manual/reference/operator/query/elemMatch/#array-of-embedded-documents

Related

Compare two values in document and display the common values in each row in result

I have documents in which am storing two main objects scan and result, I want the output such that in result I get separate row for each match of scan.location and result.location.
Date:
{
"_id" : ObjectId("6024d02a1bf5152b44baf521"),
"scan" : {
"customerId" : "e2565eac-2086-48fc-ba18-dbce74602e22",
"customerGenderSelection" : "F",
"scanQuery" : {
"service" : "MA",
"date" : "08-Nov-2020",
"locations" : [
{
"locationId" : "0023",
"locationName" : "dobson"
},
{
"locationId" : "0001",
"locationName" : "shea"
}
]
},
"sessionId" : "70511849-97f8-4318-a96e-bb3a573c52ea",
},
"result" : [
{
"employeeId" : "224f55b2-27bc-4e34-8249-a8d201540ac2",
"time" : "11:00",
"locationId" : "0023"
},
{
"employeeId" : "224f55b2-27bc-4e34-8249-a8d201540ac2",
"time" : "12:00",
"locationId" : "0023"
},
{
"employeeId" : "224f55b2-27bc-4e34-8249-a8d201540ac2",
"time" : "12:30",
"locationId" : "0023"
},
{
"employeeId" : "224f55b2-27bc-4e34-8249-a8d201540ac2",
"time" : "13:00",
"locationId" : "0001"
}
]
}
I want result where scan.scanQuery.locations.locationId == result.locationId. So expecting a result in the below format:
Expected Response:
{
"scan" : {
"customerId" : "e2565eac-2086-48fc-ba18-dbce74602e22",
"customerGenderSelection" : "F",
"scanQuery" : {
"service" : "MA",
"date" : "08-Nov-2020",
"locations" : [
{
"locationId" : "0023",
"locationName" : "dobson"
}
]
},
"sessionId" : "70511849-97f8-4318-a96e-bb3a573c52ea",
},
"result" : [
{
"employeeId" : "224f55b2-27bc-4e34-8249-a8d201540ac2",
"time" : "11:00",
"locationId" : "0023"
},
{
"employeeId" : "224f55b2-27bc-4e34-8249-a8d201540ac2",
"time" : "12:00",
"locationId" : "0023"
},
{
"employeeId" : "224f55b2-27bc-4e34-8249-a8d201540ac2",
"time" : "12:30",
"locationId" : "0023"
}
]
},
{
"scan" : {
"customerId" : "e2565eac-2086-48fc-ba18-dbce74602e22",
"customerGenderSelection" : "F",
"scanQuery" : {
"service" : "MA",
"date" : "08-Nov-2020",
"locations" :
{
"locationId" : "0001",
"locationName" : "shea"
}
]
},
"sessionId" : "70511849-97f8-4318-a96e-bb3a573c52ea",
},
"result" : [
{
"employeeId" : "224f55b2-27bc-4e34-8249-a8d201540ac2",
"time" : "13:00",
"locationId" : "0001"
}
]
}
Any suggestions or ideas would be helpful.
Try this:
db.locations.aggregate([
{
$unwind: "$scan.scanQuery.locations"
},
{
$addFields: {
result: {
$filter: {
input: "$result",
as: "item",
cond: {
$eq: ["$scan.scanQuery.locations.locationId", "$$item.locationId"]
}
}
}
}
}
]);
Output:
{
"_id": ObjectId("6024d02a1bf5152b44baf521"),
"scan": {
"customerId": "e2565eac-2086-48fc-ba18-dbce74602e22",
"customerGenderSelection": "F",
"scanQuery": {
"service": "MA",
"date": "08-Nov-2020",
"locations": {
"locationId": "0023",
"locationName": "dobson"
}
},
"sessionId": "70511849-97f8-4318-a96e-bb3a573c52ea"
},
"result": [
{
"employeeId": "224f55b2-27bc-4e34-8249-a8d201540ac2",
"time": "11:00",
"locationId": "0023"
},
{
"employeeId": "224f55b2-27bc-4e34-8249-a8d201540ac2",
"time": "12:00",
"locationId": "0023"
},
{
"employeeId": "224f55b2-27bc-4e34-8249-a8d201540ac2",
"time": "12:30",
"locationId": "0023"
}
]
},
{
"_id": ObjectId("6024d02a1bf5152b44baf521"),
"scan": {
"customerId": "e2565eac-2086-48fc-ba18-dbce74602e22",
"customerGenderSelection": "F",
"scanQuery": {
"service": "MA",
"date": "08-Nov-2020",
"locations": {
"locationId": "0001",
"locationName": "shea"
}
},
"sessionId": "70511849-97f8-4318-a96e-bb3a573c52ea"
},
"result": [
{
"employeeId": "224f55b2-27bc-4e34-8249-a8d201540ac2",
"time": "13:00",
"locationId": "0001"
}
]
}

MongoDB Return Inner Document From Array

I am trying to fetch an element from an array in a document and only the element I don't want the entire document
I tried a different method but they all return the entire document
db.dept.find({"section.classes.CRN":"1901"}).limit(100)
db.dept.where("section.classes.CRN").eq("1901").limit(100)
json
{
"_id" : ObjectId("5d70ab0c280d6b8ebb850cc1"),
"name" : "Art Studio",
"abbr" : "ARS",
"section" : [
{
"type" : "Undergraduate Courses",
"classes" : [
{
"CRN" : "193",
"Course" : "ARS100",
"Sec" : "01",
"Title" : "Drawing I",
"Cr" : "3",
"Dates" : "8/26-12/19",
"Days" : "MR",
"Time" : "1230P-0320P",
"Loc" : "SAB 226",
"Instructor" : "Schuck",
"Attributes" : "",
"Avail" : "F"
},
{
"CRN" : "293",
"Course" : "ARS100",
"Sec" : "02",
"Title" : "Drawing I",
"Cr" : "3",
"Dates" : "8/26-12/19",
"Days" : "MR",
"Time" : "0330P-0620P",
"Loc" : "SAB 226",
"Instructor" : "Itty",
"Attributes" : "",
"Avail" : "F"
},
{...
I am trying to get this or something similar when searching for a set of CRN values
json
[ {
"CRN" : "193",
"Course" : "ARS100",
"Sec" : "01",
"Title" : "Drawing I",
"Cr" : "3",
"Dates" : "8/26-12/19",
...
"Instructor" : "Schuck",
"Attributes" : "",
"Avail" : "F"
}
]
Try using the aggregate pipeline to project double nested array as:
Input:
[
{
"_id": ObjectId("5d70ab0c280d6b8ebb850cc1"),
"name": "Art Studio",
"abbr": "ARS",
"section": [
{
"type": "Undergraduate Courses",
"classes": [
{
"CRN": "193",
"Course": "ARS100",
"Sec": "01",
"Title": "Drawing I",
"Cr": "3",
"Dates": "8/26-12/19",
"Days": "MR",
"Time": "1230P-0320P",
"Loc": "SAB 226",
"Instructor": "Schuck",
"Attributes": "",
"Avail": "F"
},
{
"CRN": "293",
"Course": "ARS100",
"Sec": "02",
"Title": "Drawing I",
"Cr": "3",
"Dates": "8/26-12/19",
"Days": "MR",
"Time": "0330P-0620P",
"Loc": "SAB 226",
"Instructor": "Itty",
"Attributes": "",
"Avail": "F"
}
]
}
]
}
]
Query:
hereafter unwinding section you can filter classes for CRN
db.collection.aggregate([
{
$unwind: "$section"
},
{
$project: {
name: 1,
abbr: 1,
"section.type": 1,
"section.classes": {
$filter: {
input: "$section.classes",
as: "item",
cond: {
$eq: [
"$$item.CRN",
"193"
]
}
}
}
}
},
{
$group: {
_id: "$_id",
section: {
$push: "$section"
}
}
}
])
Output:
you can manage your keys as you want in project for adding new keys or replacing them.
[
{
"_id": ObjectId("5d70ab0c280d6b8ebb850cc1"),
"section": [
{
"classes": [
{
"Attributes": "",
"Avail": "F",
"CRN": "193",
"Course": "ARS100",
"Cr": "3",
"Dates": "8/26-12/19",
"Days": "MR",
"Instructor": "Schuck",
"Loc": "SAB 226",
"Sec": "01",
"Time": "1230P-0320P",
"Title": "Drawing I"
}
],
"type": "Undergraduate Courses"
}
]
}
]
db.dept.find({"section.classes.CRN":"1901"},{"section.classes":1}).limit(100)
It's called projection in mongodb, you pass a second object in find query to specify which fields you want in result.
so according to your above case if you want name, and section in result you should pass something like this
db.dept.find({"section.classes.CRN":"1901"},{"name":1, "section":1}).limit(100)

Querying, projecting and sorting multiple fields of documents inside a mongoDB collection

I have a simple mongoDB collection, named usersCollection, whose generale structure is this:
[
{
"username" : "john",
"sex" : "m",
"email" : "john#gmail.com",
"courses" : [
{
"title" : "medicine",
"grade": 25,
},
{
"title" : "art",
"grade": 29,
},
{
"title" : "history",
"grade": 21,
}
]
},
{
"username" : "jane",
"sex" : "f",
"email" : "jane#gmail.com",
"courses" : [
{
"title" : "math",
"grade": 20,
},
{
"title" : "medicine",
"grade": 30,
}
]
},
{
"username" : "sarah",
"sex" : "f",
"email" : "sarah#gmail.com",
"courses" : [ ]
},
{
"username" : "josh",
"sex" : "f",
"email" : "josh#gmail.com",
"courses" : [
{
"title" : "english",
"grade": 28,
}
]
},
{
"username" : "mark",
"sex" : "m",
"email" : "mark#gmail.com",
"courses" : [
{
"title" : "history",
"grade": 30,
},
{
"title" : "medicine",
"grade": 19,
},
{
"title" : "math",
"grade": 22,
}
]
}
]
Every user is a member of usersCollection and has some general informations and a list of courses that he/she has already completed with the relative grades.
Can anyone tell me how I can query usersCollection to get a descending sorted array that contains an object for all users that have already completed a specific course? Every object of this array should contains the "name", the "email" and the "grade" of the relative user.
For example, launching a query on usersCollection around the course with name "medicine", I would obtain this array:
[
{
"username": "jane",
"email": "jane#gmail.com",
"grade": 30
},
{
"username": "john",
"email": "john#gmail.com",
"grade": 25
},
{
"username": "mark",
"email": "mark#gmail.com",
"grade": 19
}
]
You can manage to do it using sort and group pipeline of mongoDB.
if you want to get any specific courses you can apply match pipeline before sort pipeline.
db.users.aggregate([
{
$unwind: "$courses"
},
{
$match: {
'courses.title': 'medicine'
}
},
{
$sort: {
'courses.title': -1,
'courses.grade': -1,
}
},
{
$group: {
_id: "$courses.title",
records: {
$push: {
"_id" : "$_id",
"username" : "$username",
"sex" : "$sex",
"email" : "$email",
"grade":"$courses.grade"
}
}
}
}
])

MongoDB query to get count of array values for specific groups

I am trying to achieve a group which tells me the count of occurrence of color and the entity count corresponding to each color.
I have written a query, But this is giving me twice the count because of unwind i guess.
My Query :
db.message.aggregate([
{$unwind: '$entities'},
{ "$group": {
"_id": {
"color": "$color",
"entities" :"$entities"
},
"count": { "$sum": 1 }
}},
{ "$group": {
"_id": "$_id.color",
"count": { "$sum": "$count" },
"entities": {
"$push": {
"entity": "$_id.entities",
"count": "$count"
},
}
}}
])
Database Message Data :
{
"_id" : ObjectId("5c55f99abf6dc481ccfa7f67"),
"color" : "Red",
"channel" : "google",
"content" : "red color",
"entities" : [
"a",
"b"
]
},
{
"_id" : ObjectId("5c57f0a0bf6dc44424e8d371"),
"color" : "Red",
"channel" : "google",
"content" : "red color",
"entities" : [
"a",
"b"
]
},{
"_id" : ObjectId("5c5947a4bf6dc462603d87da"),
"color" : "Blue",
"channel" : "google",
"content" : "yo yo",
"entities" : [
"a",
"b"
]
},
{
"_id" : ObjectId("5c6151b9bf6dc4bee8dac8c9"),
"color" : "Blue",
"handle" : "IBM",
"channel" : "twitter",
"content" : "yo yo",
"entities" : [
"a",
"b",
"c"
]
}
(EDITED) I am Expecting the following Output :
{
"color" : "Red",
"count" : 2,
"entities" : [
{
"entity" : "a",
"count" : 2
},
{
"entity" : "b",
"count" : 2
}
]
},
{
"color" : "Blue",
"count" : 2,
"entities" : [
{
"entity" : "c",
"count" : 1
},
{
"entity" : "b",
"count" : 2
},
{
"entity" : "a",
"count" : 2
}
]
}
Please Help!.

MongoDB Use $group for the subset after $group

I just learned mongoDB, I am trying to find some repeat customer info through my customer database.
The sample collection:
{
"_id" : ObjectId("5b7617e48146d8bae"),
"amazon_id" : "112",
"date" : "2018-01-25T18:40:55-08:00",
"email" : "xxxxx#marketplace.amazon.com",
"buy_name" : "xxxxx",
"sku" : "NPC-50",
"qty" : 8,
"price" : 215.92,
"reci_name" : "XXXXX",
"street1" : "XXXXX",
"street2" : "",
"street3" : "",
"city" : "XXXXX",
"state" : "XXXXX",
"zip_code" : "XXXXXX"
}
{
"_id" : ObjectId("5b761712e48146d8bae"),
"amazon_id" : "114",
"date" : "2018-01-27T18:40:55-08:00",
"email" : "xxxxx#marketplace.amazon.com",
"buy_name" : "xxxxx",
"sku" : "ABC",
"qty" : 1,
"price" : 19.99,
"reci_name" : "XXXXX",
"street1" : "XXXXX",
"street2" : "",
"street3" : "",
"city" : "XXXXX",
"state" : "XXXXX",
"zip_code" : "XXXXXX"
}
I group all customer info by their email id, and here is my code:
db.getCollection('order').aggregate([
{ $group: { _id: "$email",
OrderInfo: {$push: {orderId: "$amazon_id", sku: "$sku", qty: "$qty", price:"$price"
}},
CustomerInfo: {$addToSet: {buyName: "$buy_name",reName: "$reci_name", email: "$email", street1: "$street1",
street2: "$street2", city: "$city", state: "$state", zipCode: "$zip_code"} }
}},
{ $project: {_id: 1, OrderInfo: 1, CustomerInfo:1, total_price:{$sum: "$OrderInfo.price"} }},
{ $match: {total_price: {$gt:100} } },
{ $sort: {total_price:-1}},
], { allowDiskUse: true } );
It shows me the result:
{
"_id" : "xxxxxxx#marketplace.amazon.com",
"OrderInfo" : [
{
"orderId" : "112",
"sku" : "NPC-50",
"qty" : 8,
"price" : 215.92
},
{
"orderId" : "112",
"sku" : "NPC-50",
"qty" : 1,
"price" : 26.99
},
{
"orderId" : "114",
"sku" : "NPC-50",
"qty" : 1,
"price" : 26.99
},
{
"orderId" : "114",
"sku" : "ABC",
"qty" : 1,
"price" : 19.99
},
{
"orderId" : "116",
"sku" : "ABC",
"qty" : 1,
"price" : 19.99
},
],
"CustomerInfo" : [
{
"buyName" : "xxxxxxxxx",
"reName" : "xxxxxxxxxxxx",
"email" : "xxxxxxxxxxxx#marketplace.amazon.com",
"street1" : "xxxxxxxxxxx",
"street2" : "",
"city" : "xxxxxxxxxx",
"state" : "xxxxxxxxxxxx",
"zipCode" : "xxxxxxxxxx"
},
{
"buyName" : "xxxxxxxxxx",
"reName" : "xxxxxx",
"email" : "xxxxxxxx#marketplace.amazon.com",
"street1" : "xxxxxxxxxxx",
"street2" : "",
"city" : "xxxxx",
"state" : "xxxx",
"zipCode" : "xxxxxxxx"
}
],
"total_price" : 309.88
}
However, I want to group the sku and sum up the qty and price in the OrderInfo Set. My expected output is something like:
{
"OrderInfo" : [
{
"sku": "NPC-50",
"qty": 10,
"price": 269.9
},
{
"sku": "ABC",
"qty": 2,
"price": 39.98
},
],
"CustomerInfo" : [
{
"buyName" : "xxxxxxxxx",
"reName" : "xxxxxxxxxxxx",
"email" : "xxxxxxxxxxxx#marketplace.amazon.com",
"street1" : "xxxxxxxxxxx",
"street2" : "",
"city" : "xxxxxxxxxx",
"state" : "xxxxxxxxxxxx",
"zipCode" : "xxxxxxxxxx"
},
{
"buyName" : "xxxxxxxxxx",
"reName" : "xxxxxx",
"email" : "xxxxxxxx#marketplace.amazon.com",
"street1" : "xxxxxxxxxxx",
"street2" : "",
"city" : "xxxxx",
"state" : "xxxx",
"zipCode" : "xxxxxxxx"
}
],
"total_price" : 309.88
}
Any Help will be appreciated.
You can use below aggregation.
db.order.aggregate([
{"$group":{
"_id":{"email":"$email","sku":"$sku"},
"qty":{"$sum":"$qty"},
"price":{"$sum":"$price"},
"CustomerInfo":{
"$addToSet":{
"buyName":"$buy_name",
"reName":"$reci_name",
"email":"$email",
"street1":"$street1",
"street2":"$street2",
"city":"$city",
"state":"$state",
"zipCode":"$zip_code"
}
}
}},
{"$group":{
"_id":"$_id.email",
"OrderInfo":{"$push":{"sku":"$_id.sku","qty":"$qty","price":"$price"}},
"total_price":{"$sum":"$price"},
"CustomerInfo":{"$first":"$CustomerInfo"}
}},
{"$match":{"total_price":{"$gt":100}}},
{"$sort":{"total_price":-1}}
])
You can try below aggregation
db.collection.aggregate([
{ "$group": {
"_id": {
"email": "$email",
"sku": "$sku"
},
"CustomerInfo": {
"$addToSet": {
"buyName": "$buy_name",
"otherFields": "$otherFields",
}
},
"price": { "$sum": "$price" },
"qty": { "$sum": "$qty" }
}},
{ "$group": {
"_id": "$_id.email",
"CustomerInfo": { "$first": "$CustomerInfo" },
"OrderInfo": {
"$push": {
"sku": "$_id.sku",
"qty": "$qty",
"price": "$price"
}
}
}}
])