I am learning postgresql. I have this type of data that i want to add in my database.
{
id: (Math.random().toString(36)+'00000000000000000').slice(2, 7),
title: "This is a sample todo",
status: 'pending',
created_at: new Date(),
subTask: [
{
text: "This is a sampe subtask",
isDone: false,
},
{
text: "This is a sample subtask",
isDone: false,
}
]
}
My question is how can i update and add objects in subtasks array using postgresql queries.
I have so far tried this one
update
todos
set
subtasks = '[{"title": "Task No 2", "status": "pending"}]'
where
id = 6;
But it is only replacing the existing object present not adding it. I have also searched on the google and elsewhere but so far don't find anything.
Thank you
Related
Let's say I have a MongoDB collection "people" that has the form
[
{
_id: [OBJECT_ID_1],
name: "Paul",
hobby: "rowing",
fixed: 1
},
{
_id: [OBJECT_ID_2],
name: "Selena",
hobby: "drawing",
fixed: 2
},
{
_id: [OBJECT_ID_3],
name: "Emily",
hobby: "jogging",
fixed: 3
}
]
And new data to be inserted of the form
var data = [
{
name: "Paul", // name exists, so keep "fixed" at 1
hobby: "archery",
fixed: 4
},
{
name: "Peter",
hobby: "knitting",
fixed: 5
}
]
I would like to insert/update the collection with the new data. However, if a document with the same "name" already exists, I do not want to update "fixed". The result after inserting the above data should be
[
{
_id: [OBJECT_ID_1],
name: "Paul",
hobby: "archery", // updated
fixed: 1 // not updated, because name existed
},
{
_id: [OBJECT_ID_2],
name: "Selena",
hobby: "drawing",
fixed: 2
},
{
_id: [OBJECT_ID_3],
name: "Emily",
hobby: "jogging",
fixed: 3
},
{ // newly inserted document
_id: [OBJECT_ID_4],
name: "Peter",
hobby: "knitting",
fixed: 5
}
]
The data includes a large number of documents, so I would like to achieve this in one query if possible. What would be the best way to accomplish this? Many thanks!
bulkWrite with updateOne's with $upsert:true seems to work best for you...
bulkWrite not perform a Find operation.
Its (in my case) is necessary to control if it will create a another document.
In my case I just use find check before insert/create method.
if (collection.find({"descr":descr}).limit(1).length === 1) {
//...create method
console.log('Exists')
}
Lets say that i have the following objects in my mongodb-compass-database:
{
_id: ObjectID("randomString"),
Name: "Test1",
OtherAttribute: 187
},
{
_id: ObjectID("otherRandomString"),
Name: "Test2",
OtherAttribute: 1337
},
{
_id: ObjectID("otherRandomString2"),
Name: "Test1",
OtherAttribute: 23
}
How can I return the "Name"-value if it exist more than one time?
In the example I want to receive "Test1" or the whole object, doesnt matter.
I just need to see if there are any duplicates.
I need to use the MongoDB Compass Find-Input:
Is this possible?
Details
I develop survey application with express and struggle with some getting of data.
The case:
you can get all surveys by "GET /surveys". And every survey doc has to contains hasVoted:mongoose.Bool and optionsVote:mongoose.Map if the user has voted for the survey. (SurveySchema is bellow)
you can vote for survey by "POST /surveys/vote"
you can see the results of any survey only if you vote for it
new Schema({
question: {
type: mongoose.Schema.Types.String,
required: true,
},
options: {
type: [{
type: mongoose.Schema.Types.String,
required: true,
}]
},
optionsVote: {
type: mongoose.Schema.Types.Map,
of: mongoose.Schema.Types.Number,
},
votesCount: {
type: mongoose.Schema.Types.Number,
},
votes: {
type: [{
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
},
option: mongoose.Schema.Types.Number,
}]
},
})
Target:
So the target of the question is how to add fields hasVoted and optionsVote if there is "Vote" sub document in votes array where user===req.user.id ?
I believe you got the idea so if you have an idea how to change the schema to achieve the desired result I'm open!
Example:
Data:
[{
id:"surveyId1
question:"Question",
options:["op1","op2"],
votes:[{user:"userId1", option:0}]
votesCount:1,
optionsVote:{"0":1,"1":0}
},{
id:"surveyId2
question:"Question",
options:["op1","op2"],
votes:[{user:"userId2", option:0}]
votesCount:1,
optionsVote:{"0":1,"1":0}
}]
Route handler:
Where req.user.id='userId1' and then make the desired query.
The result
[{ // Voted for this survey
id:"surveyId1
question:"Question",
options:["op1","op2"],
votes:[{user:"userId1", option:0}]
votesCount:1,
optionsVote:{"0":1,"1":0},
hasVoted:true,
},{ // No voted for this survey
id:"surveyId2
question:"Question",
options:["op1","op2"],
votesCount:1,
}]
In MongoDB, you can search for sub document as follows
//Mongodb query to search for survey filled by a user
db.survey.find({ 'votes.user': myUserId })
So with this when you can get results only where user has voted, do you really need hasVoted field?
To have optionsVote field, first I would prefer schema of optionsVote as {option: "a", count:1}. You can choose any of the following approach.
A. manage to update optionsVote field at the time of update by incrementing the count of the voted option when you POST /survey/vote.
B. Another approach would be to calculate the optionsVote based on votes entries at the time of GET /survey. You can do this via aggregate
//Mongodb query to get optionsVote:{option: "a", count:1} from votes: { user:"x", option:"a"}
db.survey.aggregate([
{ $unwind: "$votes" },
{ $group: {
"_id": { "id": "_id", "option": "$votes.option" },
optionCount: { $sum: 1 }
}
},
{
$group: { "_id": "$_id.id" },
optionsVote: { $push : { option: "$_id.option", count: "$optionCount" } },
votes: { $push : '$votes'}
}
])
//WARNING: I haven't tested this query, this is just to show the approach -> group based on votes.option and count all votes for that option for each document and then create optionsVote field by pushing all option with their count using $push into the field `optionsVote`
I recommend approach A because I assume POST operations would be quite less than GET operations. Also it's easier to implement. Having said that, keeping query in B handy will help you with sanity check.
I have unusual response from server like this
[
{
id: 1,
name: "Alexandr",
children: [
{
id: 2,
name: "Stephan"
},
{
id: 3,
name: "Nick"
}
]
},
{
id: 4,
name: "David",
children: [
{
id: 3,
name: "Nick"
},
{
id: 6,
name: "Paul"
}
]
}
]
i would like to normalize this response to receive a diction with all people. So, i use normalizr go flat this
const people= new Schema('people');
people.define({
Children: arrayOf(people),
NotOwnChildren: arrayOf(people)
});
let normalized = normalize(response.data, arrayOf(people));
but doing like this i get an error
"When merging two people, found unequal data in their "Children" values. Using the earlier value."
How can i adjust normalizr to merge people with same id (update entities with newest data)?
It looks like you're getting two people that have differing values for one of their keys (I'm assuming your example input is truncated).
For Normalizr#2:
You can use a custom mergeIntoEntity function to resolve the issue manually.
For Normalizr#>=3.0.0, you'll need use mergeStrategy.
In my sample document, I have a campaign document that contains the _id of the document and an importData array. importData is an array of objects containing a unique date and source value.
My goal is to have an object updated with a unique date/source pair. I would like to have the new object replace any matching object. In the example below, Fred may have originally donated a TV, but I want my application to update the object to reflect he donated both a TV and a radio.
// Events (sample document)
{
"_id" : "Junky Joe's Jubilee",
"importData" : [
{
"date": "2015-05-31",
"source": "Fred",
"items": [
{item: "TV", value: 20.00},
{item: "radio", value: 5.34}
]
},
{
"date": "2015-05-31",
"source": "Mary",
"items": [
{item: "Dresser", value: 225.00}
]
}
]
}
My original thought was to do something like the code below, but not only am I updating importData with Fred's donations, I'm also blowing away anything else in the importData array:
var collection = db.collection("events");
collection.update(
{_id: "Junky Joe's Jubilee",
importData: {
date: "2015-05-31",
source: 'Fred'
},
}, // See if we can find a campaign object with this name
{
$set:
{"importData":
{
date: "2015-05-31",
source: 'Fred',
items: [
{item: "TV", value: 20.00},
{item: "radio", value: 5.34}
]
}
}
},
{upsert: true}); // Create a document if one does not exist for this campaign
When I tried pushing (instead of $set), I was getting multiple entries for the date/source combos (e.g. Fred would appear to have donated two items multiple times on "2015-05-31").
How would I go about doing that with the MongoDB native driver and NodeJS?
Try this
var collection = db.collection("events");
collection.update(
{_id: "Junky Joe's Jubilee",
importData: {
date: "2015-05-31",
source: 'Fred'
},
}, // See if we can find a campaign object with this name
{
$set:
{"importData.$":
{
date: "2015-05-31",
source: 'Fred',
items: [
{item: "TV", value: 20.00},
{item: "radio", value: 5.34}
]
}
}
},
{upsert: true}); // Create a document if one does not exist for this campaign
According to the documentation under Array update operators this should only modify the first element in the array, which matches the query.