I've been trying to modify a value in multiple arrays for a few arrays and I can't find documentation on how to do this.
My collection looks like this
"rates": [
{
"category": "Web",
"seniorityRates": [
{
"seniority": "junior",
"rate": 100
},
{
"seniority": "intermediate",
"rate": 135
},
{
"seniority": "senior",
"rate": 165
}
]
}
]
I'm just trying to modify "junior" to "beginner", this should be simple.
Thanks to these answers:
How can I update a multi level nested array in MongoDB?
MongoDB updating fields in nested array
I've manage to write that python code (pymongo), but it doesn't works...
result = my_coll.update_many({},
{
"$set":
{
"rates.$[].seniorityRates.$[j].seniority" : new
}
},
upsert=False,
array_filters= [
{
"j.seniority": old
}
]
)
The path 'rates' must exist in the document in order to apply array updates.
It correspond to this command that doesn't work either
db.projects.updateMany({},
{
$set:
{
"rates.$[].seniorityRates.$[j].seniority" : "debutant"
}
},
{ arrayFilters = [
{
"j.seniority": "junior"
}
]
}
)
clone(t={}){const r=t.loc||{};return e({loc:new Position("line"in r?r.line:this.loc.line,"column"in r?r.column:......)} could not be cloned
What am I doing wrong ?
Any help would be very appreciated
The other option could be Sample
db.collection.update({},
{
$set: {
"rates.$[].seniorityRates.$[j].seniority": "debutant"
}
},
{
arrayFilters: [
{
"j.rate": { //As per your data, you can apply the condition o rate field to modify the level
$lte: 100
}
}
]
})
Or
The actual query should work Sample
db.collection.update({},
{
$set: {
"rates.$[].seniorityRates.$[j].seniority": "debutant"
}
},
{
arrayFilters: [
{
"j.seniority": "junior"
}
]
})
The same should work in python, a sample question
So I was just dumb here, I inverted two parameters so I didn't have the correct collection in the python code...
Thanks Gibbs for pointing out where the mistake was in the mongo command.
I will not delete this post as it can help other to know how to do this kind of queries.
Related
The coursesMarks property is present in every object. So I want to push the value inside coursesMarks property, to an array and return the array to the user.
[
{
"coursesMarks": {
"_id": "634a9be567a1f07be02f71d8",
"courseCode": "cse1201",
"courseTitle": "SP"
}
},
{
"coursesMarks": {
"_id": "634a9be567a1f07be02f71db",
"courseCode": "cse1203",
"courseTitle": "DS"
}
}
]
Then expected output is:
[
{
"courses":
{
"_id": "634a9be567a1f07be02f71d8",
"courseCode": "cse1201",
"courseTitle": "SP"
},
{
"_id": "634a9be567a1f07be02f71db",
"courseCode": "cse1203",
"courseTitle": "DS"
}
}
]
I've asked a clarifying question in the comments. But if we assume that the sample data provided is a single document where the array is stored in a field named arr, then a pipeline similar to the following may be what you are looking for:
[
{
$addFields: {
courses: {
$map: {
input: "$arr",
in: "$$this.coursesMarks"
}
}
}
},
{
$unset: "arr"
}
]
Playground example here
Edit
Based on the additional information about the structure of the data, you are looking to $group things in this particular case. Therefore the relevant addition to your pipeline should look something like this:
[
...
{
$group: {
_id: null,
courses: {
$push: "$coursesMarks"
}
}
},
{
$unset: "_id"
}
]
Playground demonstration here. It includes an empty $match stage at the beginning to represent whatever additional matching logic you currently have.
I have a little problem with my command lines in MongoDB. Here is what one of my documents looks like :
{
"id": "6249c4eb85a7563e673b4360",
"collection": {
"id": "6244099cb9ebc40007ac2ce3"
},
"characters": [
{
"id": "6244074ab9ebc40007ac2cf9"
},
{
"id": "6244074ab9ebc40007ac2ce1"
}
],
}
Then, in the MongoDB shell, I try to retrieve some books according to their criteria, here is an example :
db.comic.find({
characters: {
$elemMatch:{
_id: {
$in: [
ObjectId("6244074ab9ebc40007ac2ce5")
]
}
}
},
collection: {
$elemMatch:{
_id: {
$in: [
ObjectId("6244099cb9ebc40007ac2cfb")
]
}
}
}
}).pretty()
If I remove the "collection" part, I find the books related to the characters. However, if I put back the "collection" part, I have no result. I think it's related to the fact that "collection" is not an array, but I don't know how to solve this problem, knowing that the goal is to have several collections in the search, hence the "$elemMatch" and the "$in".
Thanks in advance for your help, have a nice day.
You need to use collection._id instead of collection:{$elemMatch:{_id since $elemMatch is for finding an object inside an array.
So your query should look like:
db.comic.find({
characters: {
$elemMatch:{
_id: {
$in: [
ObjectId("6244074ab9ebc40007ac2ce5")
]
}
}
},
"collection._id": {
$in: [ObjectId("6244099cb9ebc40007ac2cfb")]
}
}).pretty()
I'm trying to use $and in mongodb stitch function to get data using 2 different condition
data = col.find( { $and: [ { "title": { title } }, { "address.countryName": { country } } ] } ).toArray;
but this shows $undefined:true in response.
please guide what is wrong in here
You need to remove {} in the condition's value
db.getCollection('test').find({
$and: [
{
"title": 'title' --> Here
},
{
"address.countryName": 'country' --> Here
}
]
})
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"
}
}])
this might be a dumb question but I'm kinda new to MongoDB so let's give it a try.
I'm creating a database on MongoDB that will be storing inputs that will be entered every five minutes. This database in an SQL format should return something like this:
The main problem comes here, I don't know If I should create a document for each idvar with the entries of every year/month/day, will it hurt the performance if I make my JSON something like this?
{
"_id" : ObjectId("xxxxxxxxxxxxxxxxxxxx"),
"IdVar" : "60502",
"Years" : [
{
"2015" : [
{
"January" : [
{
"Date_Start" : "2015-01-01",
"Date_End" : "2015-01-02"
}
],
"February" : [
{
"Date_Start" : "2015-01-01",
"Date_End" : "2015-01-02"
}
]
}
]
}
]
}
Querying over nested arrays could always seems tedious in the first place.
Consider the following collection (as proposed in the comments of this post):
[
{
"IdVar": "60502",
"dates": [
{
"start": new Date("2017-03-01"),
"end": new Date("2017-04-01")
},
{
"start": new Date("2018-04-01"),
"end": new Date("2018-06-01")
}
]
},
{
"IdVar": "1337",
"dates": [
{
"start": new Date("2016-08-01"),
"end": new Date("2016-09-01")
},
{
"start": new Date("2015-04-01"),
"end": new Date("2015-06-01")
}
]
}
]
You only want to retrieve the documents which have dates in, let's say, 2017. You may use the $elemMatch operator to do so:
db.collection.find({
dates: {
$elemMatch: {
start: {
$gte: ISODate("2017-01-01T00:00:00Z"),
$lte: ISODate("2017-12-31T00:00:00Z")
}
}
}
})
... but as you rightfully stated, this will return you the document in its entirety, unaltered. In many cases, this will suit your needs, by you may still want to project your document fields accordingly to your query: A simple way of putting this is to say the projection is the SQL-equivalent of SELECT and the query, WHERE.
As an example, The following will only return me the IdVar field of each document matching my query:
db.collection.find({
dates: {
$elemMatch: {
start: {
$gte: ISODate("2017-01-01T00:00:00Z"),
$lte: ISODate("2017-12-31T00:00:00Z")
}
}
}
},
// Project your document's fields here:
{
IdVar: true
})
... will return:
[
{
"IdVar": "60502",
"_id": ObjectId("5a934e000102030405000000")
}
]
Similarly to the query, you can use (nearly) all Mongo operators in the projection fields.
The $ operator is also pretty handy when handling nested arrays. The following code will return what you need, give it a try (MongoPlayground):
db.collection.find({
dates: {
$elemMatch: {
start: {
$gte: ISODate("2017-01-01T00:00:00Z"),
$lte: ISODate("2017-12-31T00:00:00Z")
}
}
}
},
{
"dates.$": 1
})