Related
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)
Hi i'm having a discussion object collection and a user deatils collection.
Discussion collection stores the participants username in an array of strings.
Discussion collection is as follows:
[{ "_id": "5a4dbdaab46b426863e7ead3",
"topic": "test",
"topicDesc": "test123",
"createdOn": "2018-01-04T05:37:46.088Z",
"participants": ["akhil","ben"] //[usernames]
}]
The user details collection is as follows:
[{
"_id": "59e6d6ba02e11e1814481022",
"username": "ben",
"name": "Ben S",
"email": "qwerty#123.com",
},{
"_id": "5a0431b1d6fab00cdf484677",
"username": "akhil",
"name": "Akhil Clement",
"email": "qwerty#123.com",
}]
and result JSON be like
[{ "_id": "5a4dbdaab46b426863e7ead3",
"topic": "test",
"topicDesc": "test123",
"createdOn": "2018-01-04T05:37:46.088Z",
"participants": ["akhil","ben"] //[usernames]
"participantDetails": [{
"_id": "59e6d6ba02e11e1814481022",
"username": "ben",
"name": "Ben S",
"email": "qwerty#123.com",
},{
"_id": "5a0431b1d6fab00cdf484677",
"username": "akhil",
"name": "Akhil Clement",
"email": "qwerty#123.com",
}]
}]
you need to $lookup with user collection and $group
db.dis.aggregate(
[
{$unwind : "$participants"},
{$lookup : {from : "us", localField : "participants", foreignField : "username", as : "userData"}},
{$group : {_id : {
_id : "$_id", topic : "$topic", topicDesc : "$topicDesc", createdOn : "$createdOn"
},
participants : {$push : "$participants" } ,
participantDetails : {$push : {$arrayElemAt : ["$userData", 0]}}}
},
{$project : {
_id : "$_id._id",
topic : "$_id.topic",
topicDesc : "$_id.topicDesc",
createdOn : "$_id.createdOn",
participants : 1 ,
participantDetails : 1
}}
]
).pretty()
result
{
"participants" : [
"akhil",
"ben"
],
"participantDetails" : [
{
"_id" : "59e6d6ba02e11e1814481020",
"username" : "akhil",
"name" : "Akhil Clement",
"email" : "qwerty#123.com"
},
{
"_id" : "59e6d6ba02e11e1814481021",
"username" : "ben",
"name" : "Ben S",
"email" : "qwerty#123.com"
}
],
"_id" : "5a4dbdaab46b426863e7ead3",
"topic" : "test",
"topicDesc" : "test123",
"createdOn" : "2018-01-04T05:37:46.088Z"
}
EDIT
change $push to $addToSet to avoid duplicates
I am trying to write a mongo query to return documents which have exact same email from cat1 and cat2 source.
Please help. I am including a sample collection schema with expected matching document
Sample Collection
{
"id" : "1",
"name" : "John",
"contacts" : [
{
"type" : "email",
"source": "cat1",
"detail": aa#yahoo.com
},
{
"type" : "email",
"source": "cat1",
"detail": john#yahoo.com
},
{
"type" : "email",
"source": "cat2",
"detail": john#yahoo.com
}
]
},
{
"id" : "2",
"name" : "Bell",
"contacts" : [
{
"type" : "email",
"source": "cat1",
"detail": jj#yahoo.com
},
{
"type" : "email",
"source": "cat2",
"detail": john#yahoo.com
}
]
},
{
"id" : "3",
"name" : "Sam",
"contacts" : [
{
"type" : "email",
"source": "cat1",
"detail": exmaple#yahoo.com
},
{
"type" : "email",
"source": "cat3",
"detail": exmaple#yahoo.com
}
]
}
Expected result is following because this is the document which have a common email address john#yahoo.com from both source cat1 and cat2.
Document with id 2 should not be returned because though they both have email from cat1 and cat2 source the email addresses are different.
Document with id 3 should not be returned because through the email addresses are same their category is not cat1 and cat2.
{
"id" : "1",
"name" : "John",
"contacts" : [
{
"type" : "email",
"source": "cat1",
"detail": aa#yahoo.com
},
{
"type" : "email",
"source": "cat1",
"detail": john#yahoo.com
},
{
"type" : "email",
"source": "cat2",
"detail": john#yahoo.com
}
]
}
Please try to use plain JavaScript codes to filter the same email from cat1 and cat2.
> db.collection.find().forEach(function(doc) {
var cat1Email = new Set();
var cat2Email = new Set();
doc.contacts.forEach(function(c){
if (c.source === 'cat1'){
// save the cat1 emails
cat1Email.add(c.detail);
if (cat2Email.has(c.detail)){
// if there is same email from cat2, print this document
return printjson(doc);
}
}else if(c.source === 'cat2'){
// save cat2 email
cat2Email.add(c.detail);
if (cat1Email.has(c.detail)){
// if there is same email from cat1, print this document
return printjson(doc)
}
}
});
})
I have this collection:
{
"title": "First Item",
"attributes": [
{
"id": "1",
"text": "Alpha"
},
{
"id": "2",
"text": "Bravo"
},
{
"id": "3",
"text": "Charlie"
}
]
},
{
"title": "Second Item",
"attributes": [
{
"id": "1",
"text": "Alpha"
},
{
"id": "2",
"text": "Bravo"
},
{
"id": "3",
"text": "Tango"
}
]
}
Trying search with these values for "attributes.text" field:
{ "Alpha", "Bravo", "Charlie", "Delta" }
I want to find only "First Item" document that contains at least these keys but no others.
But trying these values:
{ "Alpha", "Bravo", "Delta" }
or
{ "Alpha", "Bravo" }
I do not want to find any result (beacuse "Charlie" is missing).
Thank you
Use the $in operator to match values in the attributes object array. The following query will select all documents in the collection where the text field value of the attribute object array is either "Alpha", "Bravo" or "Delta":
dbo.collection.find({
"attributes.text": {
"$in": ["Alpha", "Bravo", "Delta"]
}
});
This will return the two documents:
/* 0 */
{
"_id" : ObjectId("551187bae3757367bf8bd915"),
"title" : "First Item",
"attributes" : [
{
"id" : "1",
"text" : "Alpha"
},
{
"id" : "2",
"text" : "Bravo"
},
{
"id" : "3",
"text" : "Charlie"
}
]
}
/* 1 */
{
"_id" : ObjectId("551187bae3757367bf8bd916"),
"title" : "Second Item",
"attributes" : [
{
"id" : "1",
"text" : "Alpha"
},
{
"id" : "2",
"text" : "Bravo"
},
{
"id" : "3",
"text" : "Tango"
}
]
}
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
How can I fetch a subarray from document?
Here is one of documents:
"director_details": {
"0": {
"AppointmentDate": "2010-06-02",
"AppointmentStatus": "CURRENT",
"AppointmentType": "SEC",
"NumAppointments": "1",
"Person": {
"CountryOfResidence": [],
"DOB": [],
"Forename": "MARK JHONSONE",
"Nationality": "NATIONALITY UNKNOWN",
"PersonAddress": {
"AddressLine": "5 PARSONS STREET",
"Country": [],
"County": "WEST MIDLANDS",
"PostTown": "DUDLEY",
"Postcode": "DY1 1JJ"
},
"PersonID": "CSeJxNkEELgkAQhe/9CvFerlpZsK0IFUSEUFZH2dyxlnK1XY3897mG5WV48/HezDDYf2cP4wVS8VwsTHuETANEkjMurgvzGK2HM9PwyQDfoW4qLQpV0rJSBGHr32he1gUQu6WtxIzLNJcgaAZkF+y3 [...]",
"Surname": "WESTWOOD",
"Title": "MR"
}
},
"1": {
"AppointmentDate": "2010-06-02",
"AppointmentStatus": "CURRENT",
"AppointmentType": "DIR",
"NumAppointments": "1",
"Occupation": "DIRECTOR",
"Person": {
"CountryOfResidence": "UNITED KINGDOM",
"DOB": "1979-11-30",
"Forename": "MARK DAVID",
"Nationality": "BRITISH",
"PersonAddress": {
"AddressLine": "5 PARSONS STREET",
"Country": [],
"County": "WEST MIDLANDS",
"PostTown": "DUDLEY",
"Postcode": "DY1 1JJ"
},
"PersonID": "CSeJxNkN0KgkAQhe97CvG+XCt/gm0jqCAihLK6lE3HWsp129XIt881TG+GMx9nZg6DF5/sabxBKpbzuWmPkGkAj/OE8dvcPIWboW8aCzLAD6jqSoVQBS1KRRC2ukbzohJAxg1tJE6YTHMJnGZA9svD [...]",
"Surname": "WESTWOOD",
"Title": "MR"
}
}
}
I want to search director which forename contains "david" and surname & title are not empty.
I have a query that works pretty fine, but it also returns extra subarray which I want to remove from output.
Ok. Suppose your document is:
{
"director_details": {
"0": {
"AppointmentDate": "2010-06-02",
...
},
"1": {
"AppointmentDate": "2010-06-02",
...
}
}
}
}
First of all, director_details in you question is not an array, it's an object. And director_details.Person.Forename: /david/ will not match by a couple of reasons:
Part of object's graph is missed, a path to Forename is director_details.1.Person.Forename.
Regexs in MongoDB are case sensitive by default, you should toggle i flag to make it case-insensitive.
The correct query that will match is: db.directors.find({"director_details.1.Person.Forename" : /DAVID/}). With current data model it is not flexible at all, as you need to specify 0 or 1.
Consider making director_details an array, like:
{
"director_details": [
{
"AppointmentDate": "2010-06-02",
...
},
{
"AppointmentDate": "2010-06-02",
...
}
]
}
In this case the query is very simple:
db.directors.find({}, {"director_details" : {$elemMatch : {"Person.Forename" : /DAVID/}}})
And here is the result of running it:
> db.directors.find({}, {"director_details" : {$elemMatch : {"Person.Forename" : /DAVID/}}}).pretty()
{
"_id" : ObjectId("52455db9cafed39bf0dee631"),
"director_details" : [
{
"AppointmentDate" : "2010-06-02",
"AppointmentStatus" : "CURRENT",
"AppointmentType" : "DIR",
"NumAppointments" : "1",
"Occupation" : "DIRECTOR",
"Person" : {
"CountryOfResidence" : "UNITED KINGDOM",
"DOB" : "1979-11-30",
"Forename" : "MARK DAVID",
"Nationality" : "BRITISH",
"PersonAddress" : {
"AddressLine" : "5 PARSONS STREET",
"Country" : [ ],
"County" : "WEST MIDLANDS",
"PostTown" : "DUDLEY",
"Postcode" : "DY1 1JJ"
},
"PersonID" : "CSeJxNkN0KgkAQhe97CvG+XCt/gm0jqCAihLK6lE3HWsp129XI",
"Surname" : "WESTWOOD",
"Title" : "MR"
}
}
]
}