Correct way to do a PATCH upsert request - rest

What is the proper way to request the following upsert to a REST API?
I'm struggling to structure a NoSQL collection, which is based on the most requested returns to the front-end application.
Suppose you have the following document:
{
'user' : {
'private_comments': [
//object available only to user 1
{
'id': 1,
'bar': 'He is very good',
'...': '...'
},
//object available only to user 2
{
'id': 2,
'bar': 'He is very bad',
'...': '...'
}
],
'public_comments': '' //infos available to all users
}
}
It is needed to upsert an element to the user.private_comments array.
According to https://www.rfc-editor.org/rfc/rfc6902#appendix-A.5, I could request a replace instruction PATCHing the following data:
{ 'op': 'replace', 'path': '/user/comments/$index', 'value': 'Actually, he is OK'}
The problem is that '$index' is unknown in this case.
A possible solution that I came up with was to create something like the following operation:
{ 'op': 'upsert', 'find_by': 'id', 'find': 1, 'path': '/user/comments', 'value': 'Nope, he really sucks' }
However, the user implementing the API should't provide the id value inside the PATCH request, because this value is already accessible via the receive token. Should I simplify the operation to:
{ 'op': 'upsert', 'path': '/user/comments', 'value': 'Nope, he really sucks' }
and treat it at the backend, so when it's and upsert operation without 'find' and 'find_by' variables I assume 'find_by': 'id' and 'find': value_from_token?
Also, I cannot do a simple GET/UPDATE at the hole document because the user doesn't receive the hole document, so an update would compromise the data.

Related

Mongodb empty object Object.keys(myObj).length return wrong values

I have an object inside collection called "childLimit".
Schema:
user: { name: {type: String}, childLimit: {dailyLimit: {type: Number} }
Now if I haven't inset any info in this object (childLimit) while creating user so it should not be there as mongo work, that fine. but when I console this it return {} empty object which is fine.
But when I console.log(Object.values(childLimit)) it console [ true, undefined, undefined, undefined ] which is strange????
Object.keys(childLimit).length return 2 but it should be 0??
Now how can I check if the object is empty?? OR if the object exist??
This seems to be about Mongoose, am I right?
Just log the keys which you count, and you will see something like follows: Mongoose-internal properties, but not your document's keys:
console.log(Object.keys(doc));
// [ '$__', 'isNew', 'errors', '$locals', '$op', '_doc' ]
What you actually want are the properties of the document. You can do this as follows:
console.log(Object.keys(doc.toObject()));
// [ 'foo', 'bar', 'baz' ]
Or alternatively (this doesn't seem to be a public API though!):
console.log(Object.keys(doc._doc));
// [ 'foo', 'bar', 'baz' ]
Note that sometimes, both can return different results.

Drupal 8-9 REST translations

I can't send PATCH request to my REST API to send node with translations.
The error is 422 Unprocessable Entity: validation failed. title: Title: this field cannot hold more than 1 values.
I was trying JSON:API and REST, but the only way I found is to manually create translations, and after that update each translation separately.
The data I'm trying to PATCH to REST is
const data = {
'type': 'charset',
'title': [
{ 'value': sName1, 'lang': 'en' },
{ 'value': sName2, 'lang': 'ru' },
],
'field_unicode_range': [{ 'from': iFrom, 'to': iTo }],
};
The JSON:API does not seem to currently support translations (Nov 2021).
"does support PATCH requests on translations: updating translations is possible" source.
There does seem to be some work going on around this is this issue

Is it possible to create indexes in Mongodb for dynamic fields?

My site has several "domains" which represent sub-sections of the site. Each "domain" has its own users with profiles, and a search page where you can search for users based on profile fields that the users fill out.
User data from the 'users' collection is structured like so:
{
username: 'shawnmichaels',
first_name: 'Shawn',
last_name: 'Michaels',
domains: [
{
name: 'domain1',
user_fields: {
'bio': 'Short bio related to domain 1',
'skills': 'Pertinent skills for domain 1'
}
},
{
name: 'domain2',
user_fields: {
'bio': 'Short bio related to domain 2',
'skills': 'Pertinent skills for domain 2'
}
}
]
}
So, users have field data across multiple domains. The domain names and field names are dynamic. There could potentially be hundreds of domains for a user and dozens of fields in a domain.
Is it possible to have some sort of dynamic index so that I can search for fields under 'domain1' without getting any matches in 'domain2'?
For example, if a user1 has "skills": ["karate", "judo"] under 'domain1', and I want to search domain2 for "karate", I don't want a match for user1.
For anyone interested, I've answered my own question after a day of research.
I'm pretty new to MongoDB and didn't realize you can query arrays by treating them like any other keys, like so:
db.users.find({domains.title: 'domain1'})
// where 'domains' is an array of object each with a 'title' key
With this knowledge, I added a text index for each field I want to be searchable:
db.users.ensureIndex({
'username': 'text',
'first_name': 'text',
'last_name': 'text',
'domains.fields.bio': 'text',
'domains.fields.skills': 'text',
'domains.fields.title': 'text',
'domains.fields.training': 'text'
}, {name: 'domain_search'})
And I structured search queries in each domain like so:
db.users.find({
'domains.title': DOMAIN_NAME,
'$text': {'$search': SEARCH_TERM}
})

MongoDB - "The dollar ($) prefixed field \'$$hashKey\' in \'fieldName".$$hashKey\' is not valid for storage.'"

While trying to update a document I'm getting the above error for the field timesToDisplay.
MongoDB version 2.6.7.
The whole model:
msg = {
'name': '',
'template': '',
'displayDurInMilliSec': 0,
'timesToDisplay': [],
'images': [],
'texts': [],
'screen': []
}
I guess I will be getting the same error with the other 3 array fields.
I've tried using $set but sill getting the same error.
The code:
function updateMessage(msg) {
var conditions = {_id: msg._id}
, update = { 'name': msg.name,
'template': msg.template,
'displayDurInMilliSec': msg.displayDurInMilliSec,
'timesToDisplay': msg.timesToDisplay,
'images': msg.images,
'texts': msg.texts,
'screen': msg.screen
}
messageModel.update(conditions, update, callback);
function callback(err, numAffected) {
if (!err) console.log(numAffected)
else console.log(err)
}
}
EDIT: The msg parameter is a document in itself:
{ _id: '557d58abd54955480db6694f',
name: 'msg99',
timesToDisplay: [ { startDate: '2015-06-19T21:00:00.000Z',
'$$hashKey': 'object:214',
endDate: '2015-06-25T21:00:00.000Z',
daysOfTheWeek: [Object],
startTimeOfDay: '11',
endTimeOfDay: '13' } ],
images: [],
texts: [],
screen: [ 1 ],
'$$hashKey': 'object:54',
displayDurInMilliSec: '40189',
template: 'templates/Template2.html' }
The $$hashkey field is added by AngularJS when working with ngRepeat or ngOptions. In the case of ngRepeat you can change the repeat string by appending track by $index to it. For using ngOptions you'll have to filter out that field yourself. AngularJS provides a quick solution for filtering it out: angular.toJson. This will filter out all fields prefixed with two dollar signs. Check out the documentation.
I realize that this isn't a MongoDB answer, but this specific error ($$hashkey), is usually due to AngularJS.

MongoDB, add new { field : value } in existing embedded document with multiple level dot notation?

What I am trying to do is add a new {field:value} for a blog post. So for example, if I wanted to start tracking impressions on websites.blog_posts.url: 'http://www.example.com/01.html' how can I add that impressions attribute for that blog post?
My current document structure:
{
email_address: 'webmaster#example.com',
password: 'random_password',
first_name: 'John',
last_name: 'Doe',
user_type: 'WEBMASTER',
newsletter: 'NO',
websites: [{
main_title: 'My Blog Website',
main_url: 'http://www.example.com',
blog_posts: [{
url: 'http://www.example.com/01.html',
title:'My first blog post',
description: 'My first description.'
}, {
url: 'http://www.example.com/02.html',
title: 'My second blog post',
description: 'My second description.'
}, {
url: 'http://www.example.com/03.html',
title: 'My third blog post',
description: 'My third description.'
}, {
url: 'http://www.example.com/04.html',
title: 'My fourth blog post',
description: 'My fourth description.'
}]
}]
}
Here is what I thought would work using update and making upsert TRUE.
db.my_collection.update( {'websites.blog_posts.url': 'http://www.example.com/01.html' }, {'$set': {'websites.blog_posts.impressions': 549}}, true )
The error that I received is:
*can't append to array using string field name [blog_posts]*
Maybe "$set" is not correct for this or maybe I can not reference that deep with dot notation? I just started using MongoDB yesterday, any help would be great.
Thank you!
What you're trying to do is not possible given your schema. Dot-notation can be multi level but if there's more than one level that is an array it can no longer be addressed using the positional operator '$'.
E.g. you'd need to do :
db.my_collection.update(
{'websites.blog_posts.url': 'http://www.example.com/01.html' },
{'$set': {'websites.$.blog_posts.$.impressions': 549}},
true );
But having two position operators in the update is not possible since MongoDB can only determine the position of an element in the first array.
Your only option is to redesign your schema to have a dedicated collection of user websites (which is better for other reasons too in this case).