Cannot find expression $oldValue in MongoDb - mongodb

db.someCollection.update({
"someArrayField.name": "apple"
},
{
$push: {
"someArrayField": {
"someCode": {
$expr: "$oldField"
},
"name": "pineapple",
}
}
})
The following is a valid mongo query, I have tested it mongoplayground.net
However, I cannot find any documentation for the $oldField expression. It basically refers to the name field that was found by "someArrayField.name" : "apple"

Related

mongo db nested object and array filter

{
"_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

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.

don't allow partially matching document to add to array with $push using updateOne function

check a document whether it is partially matching (2 or more fields) with existing documents in array('claims') with $push / $addToSet using updateOne and shouldn't allow to be pushed to array
structure is as follows:
{
"_id": ObjectId("5f50c93dda654e891c903efb"),
"claims":[
{
"username": "Foo",
"claim_id":"12345",
"claimed_at":"2020-08-31T17:18:52.818737",
},
{
"username": "Bar",
"claim_id":"54321",
"claimed_at":"2020-08-31T17:18:52.818737",
}
]
}
couldn't use $addToSet since other field value like claimed_at is not known,
if it was to match single field only like user_id it was working,
I was missing something here
db.claims.updateOne(
{
"_id": ObjectId("5f50c93dda654e891c903efb"),
"claims":{"$ne": {"username":"Foo"}}
},
{
"$push":
{
"claims":
{
"username": "Foo",
"claim_id":"12345",
"claimed_at":"2020-09-02T17:08:23.514342",
}
}
})
You can try using $elemMatch and $not,
db.claims.updateOne({
"_id": ObjectId("5f50c93dda654e891c903efb"),
claims: {
$not: {
$elemMatch: {
username: "Foo",
claim_id: "12345"
}
}
}
}, {
"$push": {
"claims": {
"username": "Foo",
"claim_id": "12345",
"claimed_at": "2020-09-02T17:08:23.514342",
}
}
})

Mongodb aggregate match query with priority on full match

I am attempting to do a mongodb regex query on a field. I'd like the query to prioritize a full match if it finds one and then partials afterwards.
For instance if I have a database full of the following entries.
{
"username": "patrick"
},
{
"username": "robert"
},
{
"username": "patrice"
},
{
"username": "pat"
},
{
"username": "patter"
},
{
"username": "john_patrick"
}
And I query for the username 'pat' I'd like to get back the results with the direct match first, followed by the partials. So the results would be ordered ['pat', 'patrick', 'patrice', 'patter', 'john_patrick'].
Is it possible to do this with a mongo query alone? If so could someone point me towards a resource detailing how to accomplish it?
Here is the query that I am attempting to use to perform this.
db.accounts.aggregate({ $match :
{
$or : [
{ "usernameLowercase" : "pat" },
{ "usernameLowercase" : { $regex : "pat" } }
]
} })
Given your precise example, this could be accomplished in the following way - if your real world scenario is a little bit more complex you may hit problems, though:
db.accounts.aggregate([{
$match: {
"username": /pat/i // find all documents that somehow match "pat" in a case-insensitive fashion
}
}, {
$addFields: {
"exact": {
$eq: [ "$username", "pat" ] // add a field that indicates if a document matches exactly
},
"startswith": {
$eq: [ { $substr: [ "$username", 0, 3 ] }, "pat" ] // add a field that indicates if a document matches at the start
}
}
}, {
$sort: {
"exact": -1, // sort by our primary temporary field
"startswith": -1 // sort by our seconday temporary
}
}, {
$project: {
"exact": 0, // get rid of the "exact" field,
"startswith": 0 // same for "startswith"
}
}])
Another way would be using $facet which may prove a bit more powerful by enabling more complex scenarios but slower (several people here will hate me, though, for this proposal):
db.accounts.aggregate([{
$facet: { // run two pipelines against all documents
"exact": [{ // this one will capture all exact matches
$match: {
"username": "pat"
}
}],
"others": [{ // this one will capture all others
$match: {
"username": { $ne: "pat", $regex: /pat/i }
}
}]
}
}, {
$project: {
"result": { // merge the two arrays
$concatArrays: [ "$exact", "$others" ]
}
}
}, {
$unwind: "$result" // flatten the resulting array into separate documents
}, {
$replaceRoot: { // restore the original document structure
"newRoot": "$result"
}
}])