Remove entry in an array of a MongoDB document - mongodb

Say I have a document that looks something like this:
{
"_id": ObjectId("50b6a7416cb035b629000001"),
"businesses": [{
"name": "Biz1",
"id": ObjectId("50b6bc953e47dc923e000001")
}, {
"name": "Biz2",
"id": ObjectId("50b6ccebae0513bf52000001")
}, {
"name": "Biz3",
"id": ObjectId("50b6d015c58b414156000001")
}, {
"name": "Biz4",
"id": ObjectId("50b6d0c8a4cdd5e356000001")
}]
}
I want to remove
{
"name": "Biz3",
"id": ObjectId("50b6d015c58b414156000001")
}
from the array of businesses. I tried this (using business name instead of id for clarity):
db.users.update({'businesses.name':'Biz3'},{$pull:{'businesses.name':'Biz3'}})
but of course it didn't work. I know that the query part is correct because I get the document back when I do this:
db.users.find({'businesses.name' : 'Biz3'})
So the problem is with the update part.

Just ran a quick lil test and this works
I think trying db.users.update({'businesses.name':'Biz3'},{$pull:{'businesses':{'name':'Biz3'}}}) should do it

Related

How to filter OData collection where attribute does not exist?

I have an OData collection where the data looks like this:
{
"#odata.context": "http://localhost:5488/odata/$metadata#folders",
"value": [
{
"name": "samples",
"_id": "79a91bc9-9083-4442-ac8d-ad30777ac8c8",
"creationDate": "2019-08-05T04:39:00.670Z",
"modificationDate": "2019-08-05T04:39:00.670Z",
"shortid": "18xQnNv"
},
{
"name": "Population",
"folder": {
"shortid": "18xQnNv"
},
"_id": "7406269b-669c-41ce-92f3-f540792df07e",
"creationDate": "2019-08-05T04:39:00.750Z",
"modificationDate": "2019-08-05T04:39:00.750Z",
"shortid": "0ppeLV"
},
{
"name": "Invoice",
"folder": {
"shortid": "18xQnNv"
},
"_id": "525aff6a-6b10-4ad6-93ce-e9c753e8ade0",
"creationDate": "2019-08-05T04:39:00.790Z",
"modificationDate": "2019-08-05T04:39:00.790Z",
"shortid": "G3i2B3"
},
{
"name": "Default",
"_id": "58daf5aa-1f13-4ff9-be1f-8cb11a812485",
"creationDate": "2019-08-07T22:56:45.160Z",
"modificationDate": "2019-08-07T22:56:45.160Z",
"shortid": "Sm8LpmP"
}
]
}
I want to exclude the objects which have the attribute "folder". I've tried using a GET request: http://localhost:5488/odata/folders?$filter=folder eq null with no luck. Is this even possible and is there a way to filter my request like this?
You might be able to use the all lambda operator to accomplish this. The operator all will always return true on empty collections. So if you make a condition that no folder attribute that actually exists will ever evaluate to true on, then the result should be a filter of only those objects that have an empty attribute.
This is just a theory. You'll need to test, but it would maybe look something like this on your sample.
http://localhost:5488/odata/folders?$filter=folder/all(f:f/shortid eq 'xxxxxx')
You didn't mention the version of OData your working with but lambda expressions are at least V4 and later. Possibly earlier, not sure.

Update items in a property with array type on MongoDB

I have a collection with documents like:
{
"_id": "Mongo ObjectID",
"some_prop": "some_value",
"features": [
{ "name": "A", "icon": "01.png" },
{ "name": "B", "icon": "02.png" }
]
}
Another document sample:
{
"_id": "Mongo ObjectID",
"some_prop": "other one",
"features": [
{ "name": "B", "icon": "02.png" },
{ "name": "C", "icon": "03.png" },
{ "name": "D", "icon": "04.png" }
]
}
Notice that in the first document and the second there is the same feature B. This occurs all over many documents.
What I need is to update all features B to a new icon, something like this:
{ "name": "B", "icon": "10.png" }
I need to apply this change for all documents that has a feature with name B.
I already did a very horrible code to get all documents and update one by one in a loop. But my guess is there is a better way to do it, maybe in a single collection.update command? I'm new in MongoDB and so far googling didnt work.
You need to use $positional operator to update the fields inside an array
db.collection.updateMany(
{ "features.name": "B" },
{ "$set": { "features.$.icon": "10.png" }}
)

MongoDB, remove nested doc in an array

I have the following structure in MongoDB and I try to remove the documents that contains specific tags. I can't seem to be able to get the $pull work.
In this example, I would like to pull the nested doc that has has tags :["BB"]
Any help will be appreciated !
{
"_id": 123,
"socialItems": {
"facebook": [{
"name": "firstFacebook",
"id": 2
}, {
"name": "secondFB",
"id": 43
}],
"instagram": [{
"name": "firstNstagram",
"id": 4
}],
"pc": [{
"name": "firstPC",
"id": 55,
"tags": [
"ab"
]
}, {
"name": "secondPC",
"id": 66,
"tags": [
"BB"
]
}]
}
}
I assume you are trying to drop the nested 'pc' doc, from the array? You also don't mention if you're using a specific driver for this, so I've assumed you're running this in the Mongo shell.
The following will remove documents from the 'pc' property, when containing the 'BB' tag.
db.collectionName.update({'socialItems.pc.tags': 'BB'}, {$pull: {'socialItems.pc': {tags: 'BB'}}})

Query inner ID in MongoDB

I have two collections
1)User -> With fields,
name as String
emailId as String
2)
Rating -> With fields,
`userId as String.` (This will be the ID of the user and Foreign Key as per SQL)
comment as String`
I have created a record for the user which looks like
{
"_id": {
"$oid": "565fe1294a27a93449751a9a"
},
"name": "Some name",
"email": "somemail#gmail.com",
"createdAt": {
"$date": "2015-12-03T06:28:57.904Z"
},
"updatedAt": {
"$date": "2015-12-03T06:28:57.904Z"
}
}
I have create a record for the Rating which looks like
{
"_id": {
"$oid": "565fefa30878764428d96be1"
},
"userId": "565fe1294a27a93449751a9a",
"comment": "just a test comment",
"createdAt": {
"$date": "2015-12-03T07:30:43.409Z"
},
"updatedAt": {
"$date": "2015-12-03T07:30:43.409Z"
}
}
Now I want to make a query where all the rating done by the user along with the user document are returned.
If I make a query like
db.user.find({
"userId" :"565fe1294a27a93449751a9a"
})
I get the result like
{
"id": "565fefa30878764428d96be1",
"userId": "565fe1294a27a93449751a9a",
"comment": "just a test comment"
}
But I want the user object as well in it something like.
{
"id": "565fefa30878764428d96be1",
"user": { "name": "Some name",
"email": "somemail#gmail.com",
"id": "565fe1294a27a93449751a9a"
},
"comment": "just a test comment"
}
Or even something like this will work as well
"rating": {
"id": "565fefa30878764428d96be1",
"userId": "565fe1294a27a93449751a9a",
"comment": "just a test comment"
},
"user": {
"id": "565fefa30878764428d96be1",
"userId": "565fe1294a27a93449751a9a",
"comment": "just a test comment"
}
Here you need to change schema. You need to change user type from string to reference. If you add reference of User in rating, then that will be easy. If you add reference of User schema then you can populate user on rating. Then will get user info with rating.
example of reference :
User: {type: mongoose.Schema.ObjectId, ref: 'User'}
Found my exact solution here. http://sailsjs.org/documentation/concepts/models-and-orm/associations/one-to-many
Technically it creates two queries in the backend. Found this out by the response time.
But anyways it solves my problem.

How to update the Embedded Data which is inside of another Embedded Data?

I have document like below in MongoDB:
{
"_id": "test",
"tasks": [
{
"Name": "Task1",
"Parameter": [
{
"Name": "para1",
"Type": "String",
"Value": "*****"
},
{
"Name": "para2",
"Type": "String",
"Value": "*****"
}
]
},
{
"Name": "Task2",
"Parameter": [
{
"Name": "para1",
"Type": "String",
"Value": "*****"
},
{
"Name": "para2",
"Type": "String",
"Value": "*****"
}
]
}
]
}
There is Embedded Data Structure (Parameter) inside of another Embedded Data Structure (Tasks). Now I want to update the para1 in Task1's Parameter.
I have tried many ways but I can only use query tasks.Parameter.name to find the para1 but cannot update it. the example in the doc are using .$. to update the value in a Embedded Data Structure but it doesn't work in my case.
Anyone have any ideas ?
MongoDB currently only supports the positional operator once, and only for the top level array. There is a ticket SERVER-831 to change this behavior for your use case. You can follow the issue there and up vote it.
However, you might be able to change your approach to accomplish what you want to do. One way is to change your schema. Collapse the tasks name into the array so the document looks like this:
{
_id:test,
tasks:
[
{
Task:1
Name:para1,
Type:String,
Value:*****
},
{
Task:1
Name:para2,
Type:String,
Value:*****
},
{
Task:2
Name:para1,
Type:String,
Value:*****
},
{
Task:2
Name:para2,
Type:String,
Value:*****
}
]
}
Another approach that may work for you is to use $pull and $push. For instance something like this to replace a task (this assumes that tasks.Parameter.Name is unique to an array of Parameters):
db.test2.update({$and: [{"tasks.Name": "Task3"}, {"tasks.Parameter.Name":"para1"}]}, {$pull: {"tasks.$.Parameter": {"Name": "para1"}}})
db.test2.update({"tasks.Name": "Task3"}, {$push: {"tasks.$.Parameter": {"Name": "para3", Type: "String", Value: 1}}})
With this solution you need to be careful with regard to concurrency, as there will be a brief moment where the document doesn't exist.