How to merge into array? - arrays

Here is my array from db,
[
{
"_id": "58144e6c0c8d7534f4307269",
"doctor_id": "5813221ace684e2b3f5f0a6d",
"prescription": [
{
"_id": "58144e6c0c8d7534f430726a",
"medicine_id": "10011241343"
}
]
I want to merge with only prescription like this
[
{
"_id": "58144e6c0c8d7534f4307269",
"doctor_id": "5813221ace684e2b3f5f0a6d",
"prescription": [
{
"_id": "58144e6c0c8d7534f430726a",
"medicine_id": "10011241343"
},
"prescription": [
{
"_id": "58144e6c0c8d7534f430726a", // it should be autogenerated
"medicine_id": "10011241344"
}
]
How can I do this?
I have tried like this
var arr = data.presription
arr=req.body// which contains only medicine id
and then by
dbModel.user.findById(data._id, function(err, data) {
data.prescription = arr;
data.save(function(err) {
if (err) {
res.status(202).json({
"success": "0",
});
} else {
res.status(200).json({
"success": "1"
});
}
})
});
But it is saving the same. How can I do this?
Note: Even when I do console.log(arr) only the old data is printing.

So data.presription is an array from the start.
data.presription.push( {
"_id": "58144e6c0c8d7534f430726a",
"medicine_id": "10011241344"
});
This is NOT a merge, what you want to do is to append (or push) items into an existing array.

Related

MongoDB - How to modify the "key" element in the document

I am having the below document structure:
[
{
"network_type": "ex",
"rack": [
{
"xxxx": {
"asn": 111111,
"nodes": {
"business": [
"sk550abcc1eb01.abc.com",
"sk550abcc1eb10.abc.com",
"sk550abcc1eb19.abc.com",
"sk550abcc1eb28.abc.com"
]
},
"region": "ex-01",
"zone": "01a"
}
}
]
}
]
I need to rename/update the key array element "xxxx" to "details".
I tried the below command, but it doesn't seem to work.
db.collection.update({},
{
$rename: {
"rack.xxxx": "details"
}
})
Link: https://mongoplayground.net/p/9dcDP-VKZ55
Please help me.
You can't direct $rename the field name which is within the array.
Instead,
Iterate with document(s) in the rank array, create the details field with the value of xxxx and next append this field to each document.
Remove the path with $rank.xxxx to remove the xxxx field from the document(s) in the rank array.
db.collection.update({},
[
{
$set: {
rack: {
$map: {
input: "$rack",
in: {
$mergeObjects: [
{
"details": "$$this.xxxx"
},
"$$this"
]
}
}
}
}
},
{
$unset: "rack.xxxx"
}
])
Sample Mongo Playground

How to delete all sub array

In my MongoDB database, I have a collection 'produits' with documents like this
{
"_id": {
"$oid": "6048e97b4a5f000096007505"
},
"modeles": [
{
"id": "OppoA3",
"pieces": [
{
"id": "OppoA3avn"
},
{
"id": "OppoA3bat"
}]
]
},
{
"id": "OppoA1",
"pieces": [
{
"id": "OppoA1avn",
},
{
"id": "OppoA1batt",
}
]
}
]
}
How can I delete all modeles.pieces from all my documents.
I managed to delete with a filter on modeles.id but with that code but not on all the collection
db.produits.update(
{marque_id:'OPPO', 'modeles.id':'RENOZ'},
{$set:
{
'modeles.$.pieces': []
}
}
, { multi : true }
)
I would like all documents like this finally
{
"_id": {
"$oid": "6048e97b4a5f000096007505"
},
"modeles": [
{
"id": "OppoA3",
"pieces": []
},
{
"id": "OppoA1",
"pieces": []
}
]
}
Thank you for your help.
I have done a javascript loop like this, but i think it's not best practice
async removePieces(){
var doc
try {
doc = await produitModel.find()
for (var produit of doc) {
for (var modele of produit.modeles) {
const filter = {'marque_id': produit.marque_id, 'modeles.id': modele.id}
const set = {
$set: {
'modeles.$.pieces': []
}
}
await db.collection('produits').updateOne(filter, set)
}
}
console.log('removePieces() ==> Terminé')
} catch(err) {
console.log(err)
}
}
db.produits.update({
modeles: {//This is because your second document will create failure otherwise
$exists: true
}
},
{
$set: {
"modeles.$.pieces": []
}
},
{
multi: true
})

Pushing to nested array inside specific element of parent array (MongoDB)

I'm rethinking how I want to structure some data which is currently being stored in the Users Collection. Previously, my server would receive messages, find the user document with the right profile.website field, and push an item into the profile.siteMessages array:
{
"_id": "hr9ck5Fis5YuvqCqP",
"profile": {
"website": "localhost",
"siteMessages": [
{
"text": "sddsd",
"createdAt": 1482001227204
},
]
}
}
Id like to change the structure to look something like the following. Instead of storing all messages, of which multiple messages could come from the same user, in a top level array in profile, I would have a profile.siteVisitors field which contains a visitorId and then the array of messages:
{
"_id": "dgfsdfdfsdf",
"emails": [
{
"address": "user2#test.com",
"verified": false
}
],
"profile": {
"website": "localhost",
"siteVisitors:" [
{
"visitorId": "74585242",
"messages": [
{
"text": "A string",
"createdAt": 1482001260853
},
{
"text": "Another string",
"createdAt": 1482001260854
}
]
},
{
"visitorId": "76672242",
"messages": [
{
"text": "A string",
"createdAt": 1482001260855
}
]
}
]
}
}
Keeping with the structure shown above, how would I query for and update the profile.siteVisitiors.messages array? Currently I query and update the Collection using something like the following:
Meteor.users.update(
{'profile.website': url},
{$push: {'profile.siteMessages': msgItem}},
function(err) {
if (err) {
console.log('whoops!' + err)
} else {
//success
}
});
How would I update the newly structured messages array? I would need to match a User documents profile.website field, match a visitorId in the profile.siteVisitors array, and then push a new element into the messages array, but I'm not sure how this would look as a MongoDB query.
EDIT I've hacked together the following which seems to work, but is very ugly. How can I improve this?
Meteor.users.update(
{"profile.website" : "localhost" , "profile.siteVisitors" : {$elemMatch: {"visitorId" : data.chirpVisitorId} } },
{$push: { "profile.siteVisitors.$.messages": {"text" : data.msg, "createdAt" : data.msg.createdAt} } },
function(err, res) {
if (err) {
console.log('failed to push ' + err)
} else {
console.log('success on new push ' + res)
if (res < 1) {
let item = {
"visitorId": data.chirpVisitorId,
"messages": [data.msg]
}
Meteor.users.update(
{"profile.website": "localhost"},
{$push: {'profile.siteVisitors': item}},
function(err, res) {
if (err) {
console.log(err)
} else {
console.log(res + " updated")
}
}
)
}
}
})
You can use the $(update) operator.
Try the following query:
db.collection.update(
{"profile.website" : "localhost" , "profile.siteVisitors" : {$elemMatch: {"visitorId" :'76672242'} } },
{ $push: { "profile.siteVisitors.$.messages": {"text" : <newText>, "createdAt" : <newCreatedDate>} } }
)
Hope this helps.

updating a JSON array in AWS dynamoDB

My document looks like this:
{
"data": {
"eventId": "20161029125458-df-d",
"name": "first",
"purpose": "test",
"location": "yokohama",
"dateArray": [],
"attendees": [
{
"attendeeId": "2016102973634-df",
"attendeeName": "lakshman",
"personalizedDateSelection": {}
},
{
"attendeeId": "2016102973634-tyyu",
"attendeeName": "diwaakar",
"personalizedDateSelection": {}
}
]
}
}
Say, I need to update the attendee JSON array with attendeeId: 2016102973634-df. I tried many ways ways using update and condition expression, but no success.
Here is my try:
const params = {
TableName: "event",
Key: {
"eventId": eventId
},
UpdateExpression: "SET attendees[???] = ",
ConditionExpression: attendees.attendeeId = "2016102973634-df",
ExpressionAttributeValues: {
":attendee" : attendeeList
},
ReturnValues: "ALL_NEW"
};
dynamo.update(params, (err, data) => {
if (err) {
return reject(err);
}
console.log(data.Attributes);
});
Could not find any resources for updating an Json in a array.
After #notionquest's comment:
- Have not used any JsonMarshaller. Initially I added the empty array to attendees field like this:
{
"eventId": "20161029125458-df-d",
"name": "first",
"purpose": "test",
"location": "yokohama",
"dateArray": [],
"attendees": []
}
and then When a new attendee comes I add it to the attendees property like this:
const attendee = {
"attendeeName": "user1",
"personalizedDateSelection": {"today": "free"}
}
const attendeeList = [attendee];
const eventId = "20161029125458-df-d";
const params = {
TableName: "event",
Key: {
"eventId": eventId
},
UpdateExpression: "SET attendees = list_append(attendees, :attendee)",
ExpressionAttributeValues: {
":attendee" : attendeeList
},
ReturnValues: "ALL_NEW"
};
dynamo.update(params, (err, data) => {
if (err) {
return reject(err);
}
console.log("in update dynamo");
console.log(data.Attributes);
});
As you have seen in the above snippets, initially I add empty [] array and add a new attendee using the above code. Now, How do I update a specific JSON in an array. If you say that is not possible, what else can I try?
Should I try this :
Get the Full JSON.
Manipulate the JSOn and change the things I want in my nodeJS.
And then update the new JSON to dynamoDB.
But this consumes two calls to dynamoDB which seems to be inefficient.
Would like to know If there is any round way ?
you can store the index of list. while updating the list we can use them. For example ,
{
"data": {
"eventId": "20161029125458-df-d",
"name": "first",
"purpose": "test",
"location": "yokohama",
"dateArray": [],
"attendees": [
{
"index":0,
"attendeeId": "2016102973634-df",
"attendeeName": "lakshman",
"personalizedDateSelection": {}
},
{
"index":1,
"attendeeId": "2016102973634-tyyu",
"attendeeName": "diwaakar",
"personalizedDateSelection": {}
}
]
}
}
const params = {
TableName: "event",
Key: {
"eventId": eventId
},
UpdateExpression: "SET attendees[attendee.index].attendeeName = :value",
ExpressionAttributeValues: {
":value" : {"S":"karthik"}
},
ReturnValues: "ALL_NEW"
};
dynamo.update(params, (err, data) => {
if (err) {
return reject(err);
}
console.log(data.Attributes);
});
An example of an update query:
Data structure (saved in DynamoDB)
{
tenant_id: 'tenant_1',
users: {
user1: {
_id: 'user1',
email_address: 'test_email_1#gmail.com'
},
user2: {
_id: 'user2',
email_address: 'test_email_2#gmail.com'
}
}
}
Data for update (used in the params)
var user = {
email_address: 'updated#gmail.com'
}
Params
var params = {
TableName: 'tenant-Master',
Key: {
"tenant_id": 'tenant_1'
},
UpdateExpression: "set #users.user1 = :value",
ExpressionAttributeNames: {
"#users": "users"
},
ExpressionAttributeValues: {
":value": user,
},
};
Explanation
By switching to a map of maps from an array of maps we can now use UpdateExpression: "set #users.user1 = :value" to update our nested object at the map of users with the id of user1.
NOTE: This method as is will REPLACE the entire map object at users.user1. Some changes will need to be made if you want to keep pre-existing data.
I could not find any answer to query and update the JSON-array. I think this may be AWS profitable motive to not allow those features. If you need to query on a particular ID other than primary key, you need to make a secondary index which is cost effective. This secondary index cost is additional to the dyn
amoDB table cost.
Since, I did not want to pay extra bucks on secondary index, I changed my dynamoDB schema to the following:
{
"data": {
"eventId": "20161029125458-df-d",
"name": "first",
"purpose": "test",
"location": "yokohama",
"dateArray": [],
"attendees": {
"2016102973634-df": {
"attendeeId": "2016102973634-df",
"attendeeName": "lakshman",
"personalizedDateSelection": {}
},
"2016102973777-df": {
"attendeeId": "2016102973777-df",
"attendeeName": "ffff",
"personalizedDateSelection": {}
}
}
}
}
Changing attendees from [] to {}. This allows me the flexibility to query particular attendeeId and change the entire JSON associated with that. Even though, this is a redundant step, I do not want to spend extra bucks on my hobby project.

Only one element returned in array

I am trying to find elements from my MongoDB database with meteor.
I managed to filter and go through the structure of my array, but the result is a single element, and not all the elements matching the criteria.
Query :
var json = Tests1VerlIR.find({}, {fields: {entries: {$elemMatch: {'payload.id': {$eq: this.params._id}} } } }).fetch();
this.response.setHeader('Content-Type', 'application/json');
this.response.end(JSON.stringify(json));
Data Structure :
{"entries":
[{"method":"POST",
"source":"ex",
"path":"/ex",
"time":1464615406900,
"payload":
{"slot_frame_number":"4",
"slot_HTUTemp":"2306",
"data":"0400f008561655270209a314",
"slot_BMEPres":"10069",
"slot_HTUHumi":"5283",
"slot_BMETemp":"2288",
"time":"1464615404",
"device":"79",
"slot_BMEHumi":"5718",
"signal":"7.22",
"id":"2"},
"_id":"574c41ee578d01af3664cbaf"},
{"method":"POST",
"source":"ex",
"path":"/ex",
"time":1464615406900,
"payload":
{"slot_frame_number":"4",
"slot_HTUTemp":"2306",
"data":"0400f008561655270209a314",
"slot_BMEPres":"10069",
"slot_HTUHumi":"5283",
"slot_BMETemp":"2288",
"time":"1464615404",
"device":"79",
"slot_BMEHumi":"5718",
"signal":"7.22",
"id":"2"},
"_id":"574c41ee578d01af3664cbaf"}, {...}]}
Response :
[
{
"_id":
{
"_str": "576155d7a605348159cd1f1a"
},
"entries":
[
{
"method": "POST",
"source": "ex",
"path": "/ex",
"time": 1464615406900,
"payload":
{
"slot_frame_number":"4",
"slot_HTUTemp":"2306",
"data":"0400f008561655270209a314",
"slot_BMEPres":"10069",
"slot_HTUHumi":"5283",
"slot_BMETemp":"2288",
"time":"1464615404",
"device":"79",
"slot_BMEHumi":"5718",
"signal":"7.22",
"id":"2"
},
"_id": "574c41ee578d01af3664cbaf"
}
]
}
]
You cannot return multiple elements of an array matching your criteria in any form of a basic .find() query. To match more than one element you need to use the .aggregate() method instead.
refer this link.
Tests1VerlIR.aggregate([
{ "$match": { "entries.payload.id": "2" } },
// Unwind the array to denormalize
{ "$unwind": "$entries" },
// Match specific array elements
{ "$match": { "entries.payload.id": "2" } },
// Group back to array form
{ "$group": {
"_id": "$_id",
"entries": { "$push": "$entries" }
}}
])
Solution :
var json = Tests1VerlIR.aggregate({"$unwind": "$entries"}, {$match: {'entries.payload.id': this.params._id} });

Resources