MongoDB find documents with a matching field in another collection - mongodb

known = [{ system_id : 1234},
{ system_id : 1235},
{ system_id : 1236},
{ system_id : 1237}]
peeps = [
{system_id: 1234, name : bob},
{system_id: 1232, name : jim},
{system_id: 1231, name : dave},
{system_id: 1237, name : jeff}
]
If I have the above two collections, and I want to find documents in the peeps collection that have system_ids that exist in documents in the known collection, how can that be done? I'm currently running an aggregation across peeps where I find all the unique combinations of name and system_id, but I need to exclude anything that is not in the known collection.

db.peeps.aggregate({
$lookup : {
from : "known",
localField : "system_id",
foreignField : "system_id",
as : "someField"
}
},{
$match : {
"someField.0" : {
$exists : true
}
}
},{
$project : {
"someField" : 0
}
})
This will output all those peeps which have system_id matched in knwon.

Related

MongoDB get all embedded documents where condition is met

I did this in my mongodb:
db.teams.insert({name:"Alpha team",employees:[{name:"john"},{name:"david"}]});
db.teams.insert({name:"True team",employees:[{name:"oliver"},{name:"sam"}]});
db.teams.insert({name:"Blue team",employees:[{name:"jane"},{name:"raji"}]});
db.teams.find({"employees.name":/.*o.*/});
But what I got was:
{ "_id" : ObjectId("5ddf3ca83c182cc5354a15dd"), "name" : "Alpha team", "employees" : [ { "name" : "john" }, { "name" : "david" } ] }
{ "_id" : ObjectId("5ddf3ca93c182cc5354a15de"), "name" : "True team", "employees" : [ { "name" : "oliver" }, { "name" : "sam" } ] }
But what I really want is
[{"name":"john"},{"name":"oliver"}]
I'm having a hard time finding examples of this without using some kind of programmatic iterator/loop. Or examples I find return the parent document, which means I'd have to parse out the embedded array employees and do some kind of UNION statement?
Eg.
How to get embedded document in mongodb?
Retrieve only the queried element in an object array in MongoDB collection
Can someone point me in the right direction?
Please add projections to filter out the fields you don't need. Please refer the project link mongodb projections
Your find query should be constructed with the projection parameters like below:
db.teams.find({"employees.name":/.*o.*/}, {_id:0, "employees.name": 1});
This will return you:
[{"name":"john"},{"name":"oliver"}]
Can be solved with a simple aggregation pipeline.
db.teams.aggregate([
{$unwind : "$employees"},
{$match : {"employees.name":/.*o.*/}},
])
EDIT:
OP Wants to skip the parent fields. Modified query:
db.teams.aggregate([
{$unwind : "$employees"},
{$match : {"employees.name":/.*o.*/}},
{$project : {"name":"$employees.name",_id:0}}
])
Output:
{ "name" : "john" }
{ "name" : "oliver" }

Mongo Db : elemMatch query on multiple array

Please find below document structure of mongo Db
{ _id : 0,
name : "Employee1",
distributionList :[ { dlname : "ALLEmployee"}, {dlname:"financeall"} ],
csrActivity : [ {activityname : "blooddonation"}, {activityname : "tree plantation"} ]
}
I want list of employee belonging to financeall distribution list and opted to volunteer tree plantation CSR activity.
Expected resultset as below
{ _id : 0,
name : "Employee1",
distributionList :[{dlname:"financeall"} ],
csrActivity : [ {activityname : "tree plantation"} ]
}
But so far able to achieve below output from query
Query :
db.employee.find(
{name : "Employee1"},
{distributionList : {$eleMatch : {dlname : "financeall"}}}
)
Output :
{ _id : 0,
name : "Employee1",
distributionList :[{dlname:"financeall"} ]
}
Using $elemMatch to get the desired output but unable to find how to use it on multiple array within same document. Also tried certain combination but unable to get desired result.
Below query tried but not getting desired output
db.employee.find(
{name : "Employee1"},
{distributionList : {$eleMatch : {dlname : "financeall"}}},
{csrActivity: {$eleMatch : {activityname : "tree plantation"}}}
)
Any help will be highly appreciated
You only misspelled the projection operator $elemMatch
The correct query is:
db.employee.find(
{
name: "Employee1"
}, {
distributionList: {
$elemMatch: {
dlname: "financeall"
}
},
csrActivity: {
$elemMatch: {
activityname: "tree plantation"
}
}
}
)

Use MongoDB _id field as composite field with multiple fields

Since every collection in mongodb has a default index on the _id column, I wanted to leverage it for my scenario as below.
I have my collection as below,
{
"_id":{
"timestamp" : ISODate("2016-08-24T23:22:20.201Z"),
"departmentname" : "sales",
"city":"NJ"
}
//Other fields in my collection
}
With this structure I am able to query as below,
db.getCollection('test').find(
{
"_id" : {
"timestamp" : ISODate("2016-08-21T23:22:20.201Z"),
"departmentname" : "sales",
"city":"NJ"
}
}
)
But, when I query by one or more fields in which are part of _id column as below,
db.getCollection('test').find(
{
"_id" : {
"timestamp" : ISODate("2016-08-21T23:22:20.201Z")
}
}
)
(OR)
db.getCollection('test').find(
{
"_id" : {
"departmentname" : "sales"
}
}
)
(OR)
db.getCollection('test').find(
{
"_id" : {
"departmentname" : "sales",
"city":"NJ"
}
}
)
I do not see any documents returned
When I checked with .explain() I see that it has used Index but did not find any documents.
Also, I would like to do date range queries on timestamp field along with query on one or more fields in the _id column like below,
db.getCollection('test').find(
{
"_id.timestamp" : {
"$gte": ISODate("2011-08-21T23:22:20.201Z")
},
"_id.departmentname" : "sales"
}
)
But, I do not see any documents returned. When I run .explain() I see it has used colscan and not index.
Can someone help me on the right way to query by one or more fields on my _id column.
Thanks,
Sri
You can try following query, in first case:-
db.getCollection('test').find(
{
"_id.timestamp" : ISODate("2016-08-21T23:22:20.201Z")
})
And this for multiple fields:
db.getCollection('test').find(
{
"_id.timestamp" : ISODate("2016-08-21T23:22:20.201Z"),
"_id.departmentname" : "sales",
})

Find oldest/youngest post in mongodb collection

I have a mongodb collection with many fields. One field is 'date_time', which is in an ISO datetime format, Ex: ISODate("2014-06-11T19:16:46Z"), and another field is 'name'.
Given a name, how do I find out the oldest/youngest post in the collection?
Ex: If there are two posts in the collection 'data' :
[{'name' : 'John', 'date_time' : ISODate("2014-06-11T19:16:46Z")},
{'name' : 'John', 'date_time' : ISODate("2015-06-11T19:16:46Z")}]
Given the name 'John' how do I find out the oldest post in the collection i.e., the one with ISODate("2014-06-11T19:16:46Z")? Similarly for the youngest post.
Oldest:
db.posts.find({ "name" : "John" }).sort({ "date_time" : 1 }).limit(1)
Newest:
db.posts.find({ "name" : "John" }).sort({ "date_time" : -1 }).limit(1)
Index on { "name" : 1, "date_time" : 1 } to make the queries efficient.
You could aggregate it as below:
Create an index on the name and date_time fields, so that the
$match and $sort stage operations may use it.
db.t.ensureIndex({"name":1,"date_time":1})
$match all the records for the desired name(s).
$sort by date_time in ascending order.
$group by the name field. Use the $first operator to get the first
record of the group, which will also be the oldest. Use the $last
operator to get the last record in the group, which will also be the
newest.
To get the entire record use the $$ROOT system variable.
Code:
db.t.aggregate([
{$match:{"name":"John"}},
{$sort:{"date_time":1}},
{$group:{"_id":"$name","oldest":{$first:"$$ROOT"},
"youngest":{$last:"$$ROOT"}}}
])
o/p:
{
"_id" : "John",
"oldest" : {
"_id" : ObjectId("54da62dc7f9ac597d99c182d"),
"name" : "John",
"date_time" : ISODate("2014-06-11T19:16:46Z")
},
"youngest" : {
"_id" : ObjectId("54da62dc7f9ac597d99c182e"),
"name" : "John",
"date_time" : ISODate("2015-06-11T19:16:46Z")
}
}
db.t.find().sort({ "date_time" : 1 }).limit(1).pretty()

MongoDb - How to search BSON composite key exactly?

I have a collection that stored information about devices like the following:
/* 1 */
{
"_id" : {
"startDate" : "2012-12-20",
"endDate" : "2012-12-30",
"dimensions" : ["manufacturer", "model"],
"metrics" : ["deviceCount"]
},
"data" : {
"results" : "1"
}
}
/* 2 */
{
"_id" : {
"startDate" : "2012-12-20",
"endDate" : "2012-12-30",
"dimensions" : ["manufacturer", "model"],
"metrics" : ["deviceCount", "noOfUsers"]
},
"data" : {
"results" : "2"
}
}
/* 3 */
{
"_id" : {
"dimensions" : ["manufacturer", "model"],
"metrics" : ["deviceCount", "noOfUsers"]
},
"data" : {
"results" : "3"
}
}
And I am trying to query the documents using the _id field which will be unique. The problem I am having is that when I query for all the different attributes as in:
db.collection.find({$and: [{"_id.dimensions":{ $all: ["manufacturer","model"], $size: 2}}, {"_id.metrics": { $all:["noOfUsers","deviceCount"], $size: 2}}]});
This matches 2 and 3 documents (I don't care about the order of the attributes values), but I would like to only get 3 back. How can I say that there should not be any other attributes to _id than those that I specify in the search query?
Please advise. Thanks.
Unfortunately, I think the closest you can get to narrowing your query results to just unordered _id.dimensions and unordered _id.metrics requires you to know the other possible fields in the _id subdocument field, eg. startDate and endDate.
db.collection.find({$and: [
{"_id.dimensions":{ $all: ["manufacturer","model"], $size: 2}},
{"_id.metrics": { $all:["noOfUsers","deviceCount"], $size: 2}},
{"_id.startDate":{$exists:false}},
{"_id.endDate":{$exists:false}}
]});
If you don't know the set of possible fields in _id, then the other possible solution would be to specify the exact _id that you want, eg.
db.collection.find({"_id" : {
"dimensions" : ["manufacturer", "model"],
"metrics" : ["deviceCount", "noOfUsers"]
}})
but this means that the order of _id.dimensions and _id.metrics is significant. This last query does a document match on exact BSON representation of _id.