MongoDB - Returning Specific Document Fields - mongodb

I have the following structure to my Mongodb documents, and as you'll see, I have 3 URLs, each with crawled set to True or False.
{
"_id": {
"$oid": "573b8e70e1054c00151152f7"
},
"domain": "example.com",
"good": [
{
"crawled": true,
"added": {
"$date": "2016-05-17T21:34:34.485Z"
},
"link": "/threads/11005-Cheap-booze!"
},
{
"crawled": false,
"added": {
"$date": "2016-05-17T21:34:34.485Z"
},
"link": "/threads/9445-This-week-s-voucher-codes"
},
{
"crawled": false,
"added": {
"$date": "2016-05-17T21:34:34.485Z"
},
"link": "/threads/9445-This-week-s-voucher-codes_2"
}
],
"link_found": false,
"subdomain": "http://www."
}
I'm trying to return specific fields where only those URL with crawled set to False are returned, for this I have the following query:
.find({'good.crawled' : False}, {'good.link':True, 'domain':True, 'subdomain':True})
However, what is returned vs what is expected is different as it's returning all the URLs, irrespective of whether they have a crawled status of True or False
What is returned is:
{
u'domain': u'cashquestions.com',
u'_id': ObjectId('573b8e70e1054c00151152f7'),
u'subdomain': u'http://www.',
u'good': [
{
u'link': u'/threads/11005-Cheap-booze!'
},
{
u'link': u'/threads/9445-This-week-s-voucher-codes'
},
{
u'link': u'/threads/9445-This-week-s-voucher-codes_2'
}
]
}
What is expected:
{
u'domain': u'cashquestions.com',
u'_id': ObjectId('573b8e70e1054c00151152f7'),
u'subdomain': u'http://www.',
u'good': [
{
u'link': u'/threads/9445-This-week-s-voucher-codes'
},
{
u'link': u'/threads/9445-This-week-s-voucher-codes_2'
}
]
}
How can I specify that only the links with crawled set to False is returned?

You'll want to use the aggregation framework (this will work in MongoDB 3.0 and later):
db.yourcolleciton.aggregate([
// optional: only those with at least one false
{$match: {'good.crawled': false}},
// get just the fields you need (plus _id)
{$project: {good:1, domain:1, subdomain: 1}},
// get each in a separate temporary document
{$unwind: {'good': 1}},
// limit to false
{$match: {'good.crawled': false}},
// undoes the $unwind
{$group: {_id: "$_id", domain: {"$first": "$domain"}, 'subdomain' : {$first, '$subdomain'}, good: {"$push":"$good"}}
])

Related

Aggregate match documents using nested documents

I have a document structure as so:
{
"name": "Bob",
"configurations": [
{
"version": 0,
"isValid": true,
"isPublished": false
},
{
"version": 1,
"isValid": false,
"isPublished": true
}
]
}
I wish to find all such document where there exists a configuration where both isValid is true and isPublished is true. For such a query, the example I gave above should not be returned since the none of the configurations have both of the flags set as true.
I first tried something like:
coll.aggregate([
{
$match: {
"configurations.isValid": true,
"configurations.isPublished": true
}
}
])
This isn't what I want because this simply checks if there exists a configuration with isValid set to true and if there also exists another configuration with isPublished set to true. I tried fixing this via:
coll.aggregate([
{
$match: {
"permissions": {
"isValid": true,
"isPublished": true
}
}
}
])
but this returns zero results. Any ideas?
EDIT:
Figured it out:
coll.aggregate([
{$match: { configurations: { $elemMatch: { $and: [ {isValid: true}, {isPublished: true} ] } } }}
])
Playground
$elemMatch will help you to find arrays with condition matches.
db.collection.find({
configurations: {
"$elemMatch": {
"isValid": true,
"isPublished": true
}
}
})
For aggregation, Example, Simply use the above in $match

Mongo DB aggregate match not returning value

I have the following mongo db schema and I am trying to build an aggregate query that searches under github_open_issues under the repo key and can return me a match for all the values with repoA as the value. I have tried the following as my query however its not returning any result. Im a bit confused why this is not working as I have another db with a schema similar to this and this type of query works there but here something seems to be different and is not working. I have also put together this interactive example mongoplayground
query
db.collection.aggregate([
{
"$unwind": "$github_open_issues"
},
{
"$match": {
"github_open_issues.repo": {
"$in": [
"repoA"
]
}
}
},
])
schema
[
{
"github_open_issues": {
"0": {
"git_url": "https://github.com/",
"git_assignees": "None",
"git_open_date": "2019-09-26",
"git_id": 253113,
"repo": "repoA",
"git_user": "userA",
"state": "open"
},
"1": {
"git_url": "https://github.com/",
"git_assignees": "None",
"git_open_date": "2019-11-15",
"git_id": 294398,
"repo": "repoB",
"git_user": "userB",
"state": "open"
},
"2": {
"git_url": "https://github.com/",
"git_assignees": "None",
"git_open_date": "2021-04-12",
"git_id": 661208,
"repo": "repoA",
"state": "open"
}
},
"unique_label_seen": {
"568": {
"label_name": "some label",
"times_seen": 12,
"535": {
"label_name": "another label",
"times_seen": 1
}
}
}
}
]
$objectToArray convert github_open_issues object to array in key-value format
$filter to iterate loop of above converted array and filter your search condition
$match to filter github_open_issues not empty
$arrayToObject convert github_open_issues array to object
db.collection.aggregate([
{
$addFields: {
github_open_issues: {
$filter: {
input: { $objectToArray: "$github_open_issues" },
cond: { $in: ["$$this.v.repo", ["repoA"]] }
}
}
}
},
{ $match: { github_open_issues: { $ne: [] } } },
{ $addFields: { github_open_issues: { $arrayToObject: "$github_open_issues" } } }
])
Playground
You query is correct but you data in schema placed wrong inside github_open_issues.repo your objects are place by numbers like {"0": {values... }, "1":{values... }} which cannot get your desired value. You can check the playground now playground

Update a subitem if it exists or insert it if not in mongodb

I'm new in here and I've just started to uses mongodb recently. I have a problem, I'm trying to update a collection's item in a given model if the item exists or update it if not.
I tried the following code but it's not working:
const res = await this.userModel.findByIdAndUpdate({
_id: user.id,
// 'devices.name': 'postman2'
}, {
$addToSet: { 'devices.[]': { name: 'postman2', generatedSecret: generatedSecret } }
}, { new: true, upsert: true }).exec();
My document looks like this:
{
"_id": {
"$oid": "5e9c6ffe9463db1594a74bec"
},
"email": "john.doe#mail.com",
"logins": [{
"provider": "email",
"secret": "sha1$e3d548b5$1$6f1b28e6b7cef47ca27b4e55ddbb6a5b8bc6b0ce"
}],
"devices": [{
"_id": {
"$oid": "5e9ddc9adb866666845bf86b"
},
"name": "postman",
"generatedSecret": "$2b$10$7fmneXGS1FjKyPXBa2Ea1erQfXF3ALjylIxOhetA9yxc3S95K4LVO"
}],
"applications": [{
"applicationId": "5e9c8b7c9463db1594a74bed"
}]
}
I want to update that devices item which matchs the query conditions. But if there isn't any matched result, then insert a new item with searched parameters.
Is possible to do this in one command?
Thanks!

Aggregation: group date in nested documents (nested object)

I've a mongo database with user information. If new userdata is added I do a duplicate check and in case of a duplicate entry, I do not create a new document, but instead update the existing one with a nested node (under tracking) adding the timestamp and some other informations.
{
"_id": "5e95dee277dcc55e9d18bf1a",
"email": "test#test.com",
"tracking": [
{
"domain": "mydomain",
"subdomain": "",
"ip": "59.214.120.68",
"timestamp": "2020-03-21 20:06:12",
"externalID": "82"
},
{
"domain": "mydomain",
"subdomain": "",
"ip": "99.214.130.33",
"timestamp": "2020-03-26 18:43:01",
"externalID": "483"
},
{
"domain": "mydomain",
"subdomain": "",
"ip": "19.214.131.22",
"timestamp": "2020-03-26 18:48:42",
"externalID": "485"
}
]
}
Now I'm trying to aggregate the documents and group/count them by date. Is there any option how I can do this with diffrent number of nodes under tracking for each document?
You can do something like this.
{
$unwind: {
path: "$tracking",
preserveNullAndEmptyArrays: true
}
}, {
$group: {
_id: "$tracking.timestamp",
count: {
$sum: 1
}
}
}
It would be much better if you could store datetimes as actual datetime type and not string representations. But assuming you cannot for now, to group by the date component without the time (which is what I believe you seek) you can use substr:
db.foo.aggregate([
{$unwind: "$tracking"}
,{$group: {"_id": {$substr: [ "$tracking.timestamp", 0, 10] } , n: {$sum:1} }}
]);

How to update multi property value of an object in array in MongoDB?

The following is my database schema update operation:
db.school_student.update({ _id: "003" }, {
$set: {
"result": [
{
"_id": "001",
"isPassed": false
},
{
"_id": "002",
"isPassed": false,
},
{
"_id": "003",
"isPassed": false
}
]
}
});
I want to change ALL the property values of "isPassed" to true. Is there any way to update this? I have been struggling with this the whole day :(
db.school_student.update({},{$Set :{"result.isPassed" : true}}
this should update all the documents in school_student collection and set isPassed to true.