mongo db nested object and array filter - mongodb

{
"_id": {
"$oid": "1234567"
},
"para": {
"lisobj": {
"abcd":
[ "1234" ]
},
}
}
I have the above mongo doc, I am trying to write a filter to see if there are any doc which have the following key:
"para.lisobj.abcd" exists.
But I am not sure what would be the proper mongo filter to find the doc which has the field.
I tried the below filter but it doesn't work:
{"para.lisobj.abcd" : { "exists": true} }

You miss $ at exists
db.collection.find({
"para.lisobj.abcd": {
$exists: true
}
})
mongoplayground

Related

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

Query nested doc's field with dot in the name

Consider such a collection:
> db.test.find({})
{ "_id" : ObjectId("5f969419d40c1580f2d4aa31"), "users" : { "foo#bar.com" : "baz" } }
{ "_id" : ObjectId("5f9694d4d40c1580f2d4aa33"), "users" : { "baz#test.com" : "foo" } }
I want to find documents where users contains field foo#bar.com.
Firstly I tried
> db.test.find({"users.foo#bar.com": { $exists: true } })
But it returned nothing. Because of the dot (.) in field's name it was looking for a such a field: users > foo#bar > com which does not exist.
I learned that the dot in key's name can be escaped with \u002e so I tried
> db.test.find({"users.foo#bar\u002ecom": { $exists: true } })
But it also returns nothing. I guess that I am not escaping properly. How should I do this?
You can do it using aggregation. Try this query.
db.test.aggregate([
{
"$project": {
"users": {
"$objectToArray": "$users"
}
}
},
{
"$match": {
"users.k": "foo#bar.com"
}
},
{
"$project": {
"users": {
"$arrayToObject": "$users"
}
}
}
])
Here is Mongo Playground
Try this one:
db.test.find({$expr:{$literal:{"users.foo#bar.com":{$exists:true}}}})
Explanation
$expr allows us to use aggregation operators in MQL
$literal returns "users.foo#bar.com" as a field (no parsing)
$literal does not touch the inner level $exists still works.

How to convert string field to object Id inside embedded document of already existing record?

I have a collection tblTesting with records saved like
{
"_id": ObjectId("5de9f044af647f21780056e1"),
"name": "abc",
"creditAccountDetails": {
"creditAccountNumber": "0200040671890190",
"creditAccountNumberId": "5db2efb5590a065abc006b12"
}
}
The embedded document "creditAccountDetails" has been wrongly saved. Now I am trying to update them by using mongodb command like
db.tblTesting.updateMany
{},
[
{ $set: { creditAccountDetails: [[ 'creditAccountNumberId' : ObjectId ($creditAccountNumber) ]] } },
{}
]
)
Basically I want that the command should be able to update all the records like
{
"_id": ObjectId("5de9f044af647f21780056e1"),
"name": "abc",
"creditAccountDetails":[ {
"creditAccountNumber": "0200040671890190",
"creditAccountNumberId": ObjectId("5db2efb5590a065abc006b12")
}
]
}
Please help!!!
Note that I am using mongo db 4.0
Since you are on mongodb version 4.0, which does not allow referring document fields in an update. A way to do this is iterate via cursor on the collection and update the field.
var cursor = db.collection.find({});
while (cursor.hasNext()) {
var doc = cursor.next();
db.collection.updateOne(
{
_id: doc._id
},
{
$set: {
creditAccountDetails: [
{
creditAccountNumber: doc.creditAccountDetails.creditAccountNumber,
creditAccountNumberId: ObjectId(
doc.creditAccountDetails.creditAccountNumberId
)
}
]
}
}
);
}
For readers who are on Mongodb 4.2.0+ which allows using aggregation pipeline ops in update methods updateOne, updateMany where document fields can be used as part of $set.
db.collection.updateMany({}, [
{
$set: {
creditAccountDetails: [
{
creditAccountNumber: "$creditAccountDetails.creditAccountNumber",
creditAccountNumberId: {
$toObjectId: "$creditAccountDetails.creditAccountNumberId"
}
}
]
}
}
]);
tblTesting's schema should have define type ObjectId for creditAccountNumberId
below example I used mongoose
const tblTesting = mongoose.Schema({
....
creditAccountNumberId: {
type: mongoose.Schema.Types.ObjectId,
},
....
}, {
collection: 'tblTesting',
timestamps: true,
strict: false,
})

$inc not working mongoDB

I have a MongoDB data like this
{
_id: "5aa8f087e1eee70004a99e1d"
users: [{facebookId: "-1", unread: 0},{facebookId: "323232321", unread: 1}]
}
I want to increment users.unread where facebookId in not "-1"
I tried this query
chat.update({ "_id": { "$in": chatId }, "users.facebookId": { "$ne": "-1" } },{"$inc": { "users.$.unread": 1 } }, { multi: true, upsert: true }, function(err, data) {
if (err) throw err;
console.log(data);
});
From MongoDB docs:
If the query matches the array using a negation operator, such as $ne, $not, or $nin, then you cannot use the positional operator to update values from this array.
However, if the negated portion of the query is inside of an $elemMatch expression, then you can use the positional operator to update this field
Below code should work if you want to increment first matching element:
db.chat.update({ "_id":"5aa8f087e1eee70004a99e1d", "users": { $elemMatch: { "facebookId": { "$ne": "-1" } }}},{"$inc": { "users.$.unread": 1 }})
Otherwise you can use array filters in MongoDB 3.6
db.col.update({ "_id":"5aa8f087e1eee70004a99e1d" }, { "$inc" : { "users.$[cond].unread" : 1 } }, { arrayFilters: [ { "cond.facebookId": { $ne: "-1" } } ] })

Mongo Update $set not working

I'm trying to mass update some mongo documents.
I'm using the query
db.articles.update(
{
'categories.id': ObjectId("51cd5272222wb6zs464fa4d9"),
'source.importer': 'pa'
},
{
$set :
{
'source.expires-at': ISODate("2014-01-01T08:39:45Z")
}
}
)
This query does not update the source.expires-at field, however the where part of the statement works fine.
The document structure is
{
"_id": ObjectId("5211dc100000044707000015"),
"categories": {
"0": {
"id": ObjectId("51cd5272222wb6zs464fa4d9")
}
},
"source": {
"importer": "pa",
"expires-at": ISODate("2013-09-18T08:49:32.0Z")
}
}
Try this:
db.articles.update(
{
'categories.id': ObjectId("51cd5272222wb6zs464fa4d9"),
'source.importer': 'pa'
},
{
$set: {
'source.expires-at': ISODate("2014-01-01T08:39:45Z")
}
},
{ multi: true }
)
You will need to pass additional option argument {multi: true};
Look in to this https://education.10gen.com/courses/10gen/M101JS/2013_August/courseware/CRUD/Multi-update/