Mongo DB update query [duplicate] - mongodb

This question already has answers here:
Can you specify a key for $addToSet in Mongo?
(2 answers)
Closed 4 years ago.
I have the below document stored in mongo DB collection,I will need to add new subscribers For eg.,I need to add the subscriber with "protocol" : "SOAP" and url http://localhost.8080/FNOL/subscriber3 for the name "name" : "FNOL","country" : "US","lob" : "property" from the document.
If the url we are adding already exist we shouldn't add to the document,in case if the document does not exist with matching criteria name "name" : "FNOL","country" : "US","lob" : "property" i would need to insert a new document.
is it possible to do all the above in a single command in mongo db?
Thanks in advance.
{
"_id" : ObjectId("5b07fbbc0d7a677d2f8b2d87"),
"name" : "FNOL",
"country" : "US",
"lob" : "property",
"subscribers" : [
{
"protocol" : "REST",
"url" : "http://localhost.8080/FNOL/subscriber1"
},
{
"protocol" : "SOAP",
"url" : "http://localhost.8080/FNOL/subscriber2"
},
{
"protocol" : "JMS",
"url" : "NOTIFICATION.TOPIC.FNOL"
}
]
}
After updation:
{
"_id" : ObjectId("5b07fbbc0d7a677d2f8b2d87"),
"name" : "FNOL",
"country" : "US",
"lob" : "property",
"subscribers" : [
{
"protocol" : "SOAP",
"url" : "http://localhost.8080/FNOL/subscriber2"
},
{
"protocol" : "JMS",
"url" : "NOTIFICATION.TOPIC.FNOL"
},
{
"protocol" : "SOAP",
"url" : "http://localhost.8080/FNOL/subscriber2"
}
,
{
"protocol" : "SOAP",
"url" : "http://localhost.8080/FNOL/subscriber3"
}
]
}

You need to use $addToSet... It will not push the data if it already exist in the array
db.collection.update(
{ name: 'FNOL', country: 'US', lob: 'property' },
{ $addToSet: { subscribers: { "protocol" : "SOAP", url: 'http://localhost.8080/FNOL/subscriber3' } } },
{ upsert: true }
)

Try this.
db.collection.update( { "_id": (id of the object) }, { "$push": {"subscribers": { "url": "(input url )", "protocol": "(input protocol)" } } } )

Related

How to query element from array with two conditions (MongoDB)

I need to query all document where groupData.users.userId = 'aFHJBrKu54y5mWjY3' AND groupData.users.userId = 'pending'.
{
"_id" : "Au2NH2iMwGfGtzqzH",
"name" : "Toyota",
"profileType" : "group",
"groupData" : {
"private" : false,
"users" : [
{
"userId" : "9qcHtd4sRFZQpPaHD",
"role" : "admin",
"addedAt" : ISODate("2020-09-16T17:23:28.266Z")
},
{
"userId" : "CnugxoBWs4ox6vG2k",
"role" : "member",
"addedAt" : ISODate("2020-09-16T17:23:37.292Z")
},
{
"userId" : "aFHJBrKu54y5mWjY3",
"role" : "pending",
"addedAt" : ISODate("2020-09-16T17:23:41.878Z")
},
{
"userId" : "GoXMTJKCWSpRdyn7c",
"role" : "member",
"addedAt" : ISODate("2020-09-16T17:23:51.281Z")
}
]
}
}
I trying the following:
const profiles = Profiles.find({
'groupData.users.userId': this.userId,
'groupData.users.role': 'pending'
}).fetch();
But it returns wrong profiles. Thank you!
You can get with elemMatch. But you need to be aware of Positional operator in projection
db.collection.find({
"groupData.users": {
"$elemMatch": {
userId: "aFHJBrKu54y5mWjY3",
role: "pending"
}
}
},
{
"groupData.users.$": 1
})
Working Mongo playground

How to upsert nested array object mongodb

I have a document which looks like this
{
_id:'asasasasa23sdsdsd',
source:'page',
url:[]
}
I need to upsert some values/objects to the url array. the objects that need to be upserted looks like this.
{
"type" : "blog",
"value" : "hello blog",
"id" : "1815f620-b45c-4230-85bb-7ba90ac330ed",
"datetime" : "2019-12-26 15:58:33"
}
Then it would look like this
{
_id:'asasasasa23sdsdsd',
source:'page',
url:[{
"type" : "admin",
"value" : "hello admin",
"id" : "1815f620-b45c-4230-85bb-7ba90ac330ed",
"datetime" : "2019-12-26 15:58:33"
},
{
"type" : "blog",
"value" : "hello blog",
"id" : "1815f620-b45c-4230-85bb-7ba90ac330ed",
"datetime" : "2019-12-26 15:58:33"
}
]
}
Here the id and the type fields are unique. I need to insert them if they do not exist or update them if they do.
This is the code that I have tried
db.collection(TABLE_NAME).update(
{ source: data.source },
{
source: data.source,
url: [data.urls]
},
{ upsert: true }
);
With this, it just replaces the array object with a new object. How to upsert instead of replacing the object?
I think this code will help.
let arr = [
{
"type" : "admin",
"value" : "hello admin",
"id" : "1815f620-b45c-4230-85bb-7ba90ac330ed",
"datetime" : "2019-12-26 15:58:33"
},
{
"type" : "blog",
"value" : "hello blog",
"id" : "1815f620-b45c-4230-85bb-7ba90ac330ed",
"datetime" : "2019-12-26 15:58:33"
}
];
db.users.update(
{ _id: doc._id },
{
$set: {
"url": arr
}
}
);

How to update multiple values in nested documents?

I am totally new to MongoDB. I have profiles document and each profile contains languages document.
{
"_id" : ObjectId("5d23134bbd43c3208034f86f"),
"name" : "name1",
"languages" :
[
{
"_id" : ObjectId("5d26321e920fba2c147dec73"),
"language" : "English",
"proficiency" : "elem"
},
{
"_id" : ObjectId("5d2632a5920fba2c147dec74"),
"language" : "Italian",
"proficiency" : "prof"
}
],
"status" : "ACTIVE"
},
{
"_id" : ObjectId("5d231352bd43c3208034f870"),
"name" : "name2",
"languages" :
[
{
"_id" : ObjectId("5d26321e920fba2c147dec75"),
"language" : "Russian",
"proficiency" : "elem"
},
{
"_id" : ObjectId("5d2632a5920fba2c147dec76"),
"language" : "Ukranian",
"proficiency" : "inter"
}
],
"status" : "ARCHIVED"
}
I would like to update all proficiencies in the profiles document (elem -> elementary, inter -> intermediate, prof -> proficient). Any help?
You need $ positional filtered operator
db.col.updateMany({},
{
$set: {
"languages.$[elem].proficiency": "elementary",
"languages.$[inter].proficiency": "intermediate",
"languages.$[prof].proficiency": "proficient",
}
},
{
arrayFilters: [
{ "elem.proficiency": "elem" },
{ "inter.proficiency": "inter" },
{ "prof.proficiency": "prof" },
]
})

Delete one element from an array in MongoDB? [duplicate]

This question already has answers here:
How to remove array element in mongodb?
(6 answers)
Closed 4 years ago.
I have the below document stored in mongo DB collection,I will dynamically receive the url to be removed For eg.,I need to delete the subscribers url http://localhost.8080/FNOL/subscriber1 for the name "name" : "FNOL","country" : "US","lob" : "property" from the document.
How do i write the remove command with mongo?
Do i need to redefine my document structure?
Thanks in advance.
{
"_id" : ObjectId("5b07fbbc0d7a677d2f8b2d87"),
"name" : "FNOL",
"country" : "US",
"lob" : "property",
"subscribers" : [
{
"protocol" : "REST",
"url" : "http://localhost.8080/FNOL/subscriber1"
},
{
"protocol" : "SOAP",
"url" : "http://localhost.8080/FNOL/subscriber2"
},
{
"protocol" : "JMS",
"url" : "NOTIFICATION.TOPIC.FNOL"
}
]
}
After removal:
{
"_id" : ObjectId("5b07fbbc0d7a677d2f8b2d87"),
"name" : "FNOL",
"country" : "US",
"lob" : "property",
"subscribers" : [
{
"protocol" : "SOAP",
"url" : "http://localhost.8080/FNOL/subscriber2"
},
{
"protocol" : "JMS",
"url" : "NOTIFICATION.TOPIC.FNOL"
}
]
}
You can use $pull operator specifying mentioned conditions to get matching document and url as a parameter of $pull like below:
let urlToRemove = "http://localhost.8080/FNOL/subscriber1";
db.col.update(
{ name: "FNOL", country: "US", lob: "property" },
{ $pull: { subscribers: {url: urlToRemove }}})

Mongodb : get whether a document is the latest with a field value and filter on the result

I am trying to port an existing SQL schema into Mongo.
We have document tables, with sometimes several times the same document, with a different revision but the same reference. I want to get only the latest revisions of the documents.
A sample input data:
{
"Uid" : "xxx",
"status" : "ACCEPTED",
"reference" : "DOC305",
"code" : "305-D",
"title" : "Document 305",
"creationdate" : ISODate("2011-11-24T15:13:28.887Z"),
"creator" : "X"
},
{
"Uid" : "xxx",
"status" : "COMMENTED",
"reference" : "DOC306",
"code" : "306-A",
"title" : "Document 306",
"creationdate" : ISODate("2011-11-28T07:23:18.807Z"),
"creator" : "X"
},
{
"Uid" : "xxx",
"status" : "COMMENTED",
"reference" : "DOC306",
"code" : "306-B",
"title" : "Document 306",
"creationdate" : ISODate("2011-11-28T07:26:49.447Z"),
"creator" : "X"
},
{
"Uid" : "xxx",
"status" : "ACCEPTED",
"reference" : "DOC501",
"code" : "501-A",
"title" : "Document 501",
"creationdate" : ISODate("2011-11-19T06:30:35.757Z"),
"creator" : "X"
},
{
"Uid" : "xxx",
"status" : "ACCEPTED",
"reference" : "DOC501",
"code" : "501-B",
"title" : "Document 501",
"creationdate" : ISODate("2011-11-19T06:40:32.957Z"),
"creator" : "X"
}
Given this data, I want this result set (sometimes I want only the last revision, sometimes I want all revisions with an attribute telling me whether it's the latest):
{
"Uid" : "xxx",
"status" : "ACCEPTED",
"reference" : "DOC305",
"code" : "305-D",
"title" : "Document 305",
"creationdate" : ISODate("2011-11-24T15:13:28.887Z"),
"creator" : "X",
"lastrev" : true
},
{
"Uid" : "xxx",
"status" : "COMMENTED",
"reference" : "DOC306",
"code" : "306-B",
"title" : "Document 306",
"creationdate" : ISODate("2011-11-28T07:26:49.447Z"),
"creator" : "X",
"lastrev" : true
},
{
"Uid" : "xxx",
"status" : "ACCEPTED",
"reference" : "DOC501",
"code" : "501-B",
"title" : "Document 501",
"creationdate" : ISODate("2011-11-19T06:40:32.957Z"),
"creator" : "X",
"lastrev" : true
}
I already have a bunch of filters, sorting, and skip/limit (for pagination of data), so the final result set should be mindful of these constraints.
The current "find" query (built with the .Net driver), which filters fine but gives me all revisions of each document:
coll.find(
{ "$and" : [
{ "$or" : [
{ "deletedid" : { "$exists" : false } },
{ "deletedid" : null }
] },
{ "$or" : [
{ "taskid" : { "$exists" : false } },
{ "taskid" : null }
] },
{ "objecttypeuid" : { "$in" : ["xxxxx"] } }
] },
{ "_id" : 0, "Uid" : 1, "lastrev" : 1, "title" : 1, "code" : 1, "creator" : 1, "owner" : 1, "modificator" : 1, "status" : 1, "reference": 1, "creationdate": 1 }
).sort({ "creationdate" : 1 }).skip(0).limit(10);
Using another question, I have been able to build this aggregation, which gives me the latest revision of each document, but with not enough attributes in the result:
coll.aggregate([
{ $sort: { "creationdate": 1 } },
{
$group: {
"_id": "$reference",
result: { $last: "$creationdate" },
creationdate: { $last: "$creationdate" }
}
}
]);
I would like to integrating the aggregate with the find query.
I have found the way to mix aggregation and filtering:
coll.aggregate(
[
{ $match: {
"$and" : [
{ "$or" : [
{ "deletedid" : { "$exists" : false } },
{ "deletedid" : null }
] },
{ "$or" : [
{ "taskid" : { "$exists" : false } },
{ "taskid" : null }
] },
{ "objecttypeuid" : { "$in" : ["xxx"] } }
]
}
},
{ $sort: { "creationdate": 1 } },
{ $group: {
"_id": "$reference",
"doc": { "$last": "$$ROOT" }
}
},
{ $sort: { "doc.creationdate": 1 } },
{ $skip: skip },
{ $limit: limit }
],
{ allowDiskUse: true }
);
For each result node, this gives me a "doc" node with the document data. It has too much data still (it's missing projections), but it's a start.
Translated in .Net:
FilterDefinitionBuilder<BsonDocument> filterBuilder = Builders<BsonDocument>.Filter;
FilterDefinition<BsonDocument> filters = filterBuilder.Empty;
filters = filters & (filterBuilder.Not(filterBuilder.Exists("deletedid")) | filterBuilder.Eq("deletedid", BsonNull.Value));
filters = filters & (filterBuilder.Not(filterBuilder.Exists("taskid")) | filterBuilder.Eq("taskid", BsonNull.Value));
foreach (var f in fieldFilters) {
filters = filters & filterBuilder.In(f.Key, f.Value);
}
var sort = Builders<BsonDocument>.Sort.Ascending(orderby);
var group = new BsonDocument {
{ "_id", "$reference" },
{ "doc", new BsonDocument("$last", "$$ROOT") }
};
var aggregate = coll.Aggregate(new AggregateOptions { AllowDiskUse = true })
.Match(filters)
.Sort(sort)
.Group(group)
.Sort(sort)
.Skip(skip)
.Limit(rows);
return aggregate.ToList();
I'm pretty sure there are better ways to do this, though.
You answer is pretty close. Instead of $last, $max is better.
About $last operator:
Returns the value that results from applying an expression to the last document in a group of documents that share the same group by a field. Only meaningful when documents are in a defined order.
Get the last revision in each group, see code below in mongo shell:
db.collection.aggregate([
{
$group: {
_id: '$reference',
doc: {
$max: {
"creationdate" : "$creationdate",
"code" : "$code",
"Uid" : "$Uid",
"status" : "$status",
"title" : "$title",
"creator" : "$creator"
}
}
}
},
{
$project: {
_id: 0,
Uid: "$doc.Uid",
status: "$doc.status",
reference: "$_id",
code: "$doc.code",
title: "$doc.title",
creationdate: "$doc.creationdate",
creator: "$doc.creator"
}
}
]).pretty()
The output as your expect:
{
"Uid" : "xxx",
"status" : "ACCEPTED",
"reference" : "DOC501",
"code" : "501-B",
"title" : "Document 501",
"creationdate" : ISODate("2011-11-19T06:40:32.957Z"),
"creator" : "X"
}
{
"Uid" : "xxx",
"status" : "COMMENTED",
"reference" : "DOC306",
"code" : "306-B",
"title" : "Document 306",
"creationdate" : ISODate("2011-11-28T07:26:49.447Z"),
"creator" : "X"
}
{
"Uid" : "xxx",
"status" : "ACCEPTED",
"reference" : "DOC305",
"code" : "305-D",
"title" : "Document 305",
"creationdate" : ISODate("2011-11-24T15:13:28.887Z"),
"creator" : "X"
}