findOneAndUpdate in mongoose - node.js

I have a json documnent lit this:
{ "mainData": { "id": "2131231312.." "data": { "oneNode": { ... } "otherNode": { ... } "anyNode": { .... } } }
In PATCH someone send me:
{
"mainData": {
"id" "2131231312.."
"oneNode": {
"field1": "value"
}
}
}
Trying to use findOneAndUpdate() to change an object inside subnode.
I'd like to change a value in "oneNode" or create node "oneNode" in "data" is not presente.
Any suggestions?
Thanks.
I use
DBValue.findOneAndUpdate({ "mainData.id": instanceId }, { "mainData": { "id" "2131231312..", "oneNode": { "field1": "value"}})

If I understand your question correctly, you can use the $set operator to only set specific points of data to the document. It can be used to update existing values OR to add new values.
https://www.mongodb.com/docs/manual/reference/operator/update/set/
Perhaps something like this:
DBValue.findOneAndUpdate(
{ "mainData.id": instanceId },
{
$set: {
'mainData.someExistingNode.someField': 1234,
'mainData.someNewField': 22
}
}
)

Related

MongoDB updating array of objects does not work as expected

Got multiple documents in a db one of which looks like this:
{
"searchWord":[
"pizz",
"pizza"
],
"result":[
{
"idMeal":1,
"strMeal":"test1",
"strInstructions":"test1"
},
{
"idMeal":2,
"strMeal":"test2",
"strInstructions":"test2"
}
]
}
Tried to solve it like this:
eg:
db.meals.updateOne(
{
"searchWord": "pizz",
"result": { $elemMatch: { idMeal: "1" } }
},
{ $set: { 'result.$.strMeal' : "UPDATED" } }
)
This doesnt update the respective subdocument only the 2nd as if I wrote
{ $set: { 'result.1.strMeal' : "UPDATED" } }
(Which will result in the 2nd subdocument being updated)
This is the other idea (Same result)
db.meals.updateOne(
{ searchWord: "pizz", 'result.idMeal': 319012 },
{ $set: { "result.$.strMeal" : "fsdf" } }
)
What I dont seem to understand is its exactly the syntax that is provided by mongo yet it doesnt work
The "$" operator doesnt pick up which array of objects I wanna update
Try to use $[] in your $set for multiple positional element
db.collection.update({
"searchWord": "pizz"
},
{
$set: {
"result.$[r].strMeal": "UPDATED"
}
},
{
arrayFilters: [
{
"r.idMeal": 1
}
]
})
Here is the Mongo playground for your reference.

Find when the keys are unkown in mongodb

How can I getthe data that has email as abc#gmail.com in mongoDB?I don't know the Key Name and I want to iterate through all the data.
I have data like this:
{
"_id":"5c0a1589a5a41b2ae707317b",
"test1":{
"email":"abc#gmail.com",
"phoneNo":"123456897",
"endpointId":"test1"
}
}
{
"_id":"5c0a1989a5a41b2ae807317b",
"test2":{
"email":"abc#gmail.com",
"phoneNo":"123456897",
"endpointId":"test2"
}
}
{
"_id":"5c0a1989a5a41b2ae807317b",
"test2":{
"email":"pqr#gmail.com",
"phoneNo":"123456897",
"endpointId":"test3"
}
}
But the object key is not known at the time of searching. I want to iterate through all the data and get matched data that has specific email.
If I know the key name like test1,test2 etc then I can use find({test1:{...}}) but Here I don't know the key value.
So, how can I do that?
You can use below aggregation using $objectToArray in mongodb 3.4 and above
db.collection.aggregate([
{ "$addFields": {
"field": { "$objectToArray": "$$ROOT" }
}},
{ "$match": { "field.v.email": "abc#gmail.com" }},
{ "$project": { "field": 0 }}
])
I am assuming you get the objects in array type.
I made a method named findObject. This method will take the object array and the desired email.
Finally, return the first object, that matched with the email.
const data = [{
"_id":"5c0a1589a5a41b2ae707317b",
"test1":{
"email": "abc#gmail.com",
"phoneNo": "123456897",
"endpointId":"test1"
}
},
{
"_id":"5c0a1989a5a41b2ae807317b",
"test2":{
"email": "abc#gmail.com",
"phoneNo": "123456897",
"endpointId":"test2"
}
},
{
"_id":"5c0a1989a5a41b2ae807317b",
"test2":{
"email": "pqr#gmail.com",
"phoneNo": "123456897",
"endpointId": "test3"
}
}];
const findObject = (data, email) => {
for (let index=0; index<data.length; index++) {
const currentData = data[index];
for (let property in currentData) {
if (property != '_id' && currentData[property].email == email) {
return currentData;
}
}
}
return null;
}
let desiredObject;
const desiredEmail = 'abc#gmail.com';
desiredObject = findObject(data, desiredEmail);
console.log(desiredObject);
And the output will be
{ _id: '5c0a1589a5a41b2ae707317b',
test1:
{ email: 'abc#gmail.com',
phoneNo: '123456897',
endpointId: 'test1' } }
I think you can't do query on totally unknown field! if you could change your schema see here for more info, also you could write script to migrate to a new DB with new schema:
// new doc instance
{
"_id":"5c0a1589a5a41b2ae707317b",
"obj": {
"name": "test1"
"email":"abc#gmail.com"
"phoneNo":"123456897",
"endpointId":"test1"
}
},
{
"_id":"5c0a1989a5a41b2ae807317b",
"obj": {
"name": "test2"
"email":"abc#gmail.com"
"phoneNo":"123456897",
"endpointId":"test2"
}
},
{
"_id":"5c0a1989a5a41b2ae807317b",
"obj": {
"name": "test3"
"email":"pqr#gmail.com"
"phoneNo":"123456897",
"endpointId":"test3"
}
}
otherwise, check this may works correctly. if all of them is not effective so make a query to get all of your data as an Array and use filter method on it:
Model.find({}, (err, docs) => {
const result = docs.filter((doc) => {
for (key in doc) {
if (doc[key].email === 'abc#gmail.com')
return doc;
}
});
console.log(result);
});

Conflict when updating a document with both $set and $currentDate

I’m using Mongo 3.6.3 and I have a database with a collection and an item with _id equal to 1.
I want to update the item by adding an object and a timestamp inside of that object. However, I get an error. Here’s what I do:
function MyObject() {
this.bar = {
apples: 4,
bananas: 5
};
}
collection.update({
_id: 1
}, {
$set: {
"foo": new MyObject()
},
$currentDate: {
"foo.time": {
$type: 'timestamp'
}
}
}, function (err) {
console.log(err.name, err.message);
});
and I get:
MongoError Updating the path 'foo.time' would create a conflict at 'foo'
Why does that happen?
If I run the $set operation first and then the $currentDate one in another update(), I get the desired result:
{
"_id" : 1,
"foo" : {
"bar" : {
"apples" : 4,
"bananas" : 5
},
"time" : Timestamp(1523459420, 1)
}
}
However, if I try to do them simultaneously like I’ve shown in the code above, I get the error. Why?
You can't have multiple operators ($set and $currentDate) that modify the same path (foo in this case). In your case you could use dot notation though:
collection.update({
_id: 1
}, {
$set: {
"foo.bar.apples": 4,
"foo.bar.bananas": 5
},
$currentDate: {
"foo.time": {
$type: 'timestamp'
}
}
}, function (err) {
console.log(err.name, err.message);
});
or just change MyObject to set this.time = new Date() instead of using $currentDate.

Mongodb: Find documents with array where at least one element does not match ObjectID

I am struggling with a MongoDB request. I have a Play schema that holds an array of Move objects. Each Move object holds a reference to a Player in the form of an ObjectID. Following this question I tried to do
{ 'moves.player': { $elemMatch : { $ne : playerId } } }
where playerId holds an ObjectID. However I get the error
Error: Can't use $elemMatch with ObjectId
I have also tried the following
{ 'moves.player.str': { $elemMatch : { $ne : playerId.toString() } } }
but it doesn't find the proper documents... Any ideas?
Example
Some Play records:
A = {
"moves": [
{ player: { $oid: "56f32fe2f41638de3b3e4773" } },
{ player: { $oid: "56f32fe2f41638de3b3e4774" } }
]
}
B = {
"moves": [
{ player: { $oid: "56f32fe2f41638de3b3e4773" } }
]
}
Query for playerId = "56f32fe2f41638de3b3e4773" should only return object A, since it is the only one that has an array of moves where at least one of the players is different from 56f32fe2f41638de3b3e4773.
OK, found out where the problem was... Just do
{ "moves": { $elemMatch: { "player": { $ne : playerId } } } }
and it works out fine!

How to remove subdocument in mongoose by array key?

I have a document like this:
{
project: 'Book',
author: 'Author',
pages: [{},{},{},{}]
}
for example I want to remove second element from pages array. I try to do something like this:
db.t.update(_id: "53296f43630a817c1af2a3e8"}, {$pull:{'test.$':1}})
but it isn't work for me.
Well the way you put it, it's going to be hard to match because there is nothing in there. But in the real world you would probably try to match like this:
db.t.update(
{ "_id": "53296f43630a817c1af2a3e8" },
{ "$pull": { "pages": { "value": 1 } }
)
That is assuming that there is a "value" property in the "sub-document".
But if you really do mean something like this where the is nothing to match, then try this:
db.t.update(
{ "_id": "53296f43630a817c1af2a3e8" },
{ "$set": { "pages.1": false } }
);
db.t.update(
{ "_id": "53296f43630a817c1af2a3e8" },
{ "$pull": { "pages": false } }
)
Which sets a value you can match and then matches and removes it.

Resources