I am using the module Mongoose for MongoDB. Everytime the user submits data to my node server, it is processed something like this:
var personSchema = mongoose.Schema({ //a new schema
properties: {}, //dynamic properties
keys: [],
houses:[],
family:[]
}, {strict: false});
var NewPerson = mongoose.model('people', personSchema);//
var personObject = {properties: {
keys: ['data that was pushed previously'];
houses: ['data that was pushed previously'];
family: ['data that was pushed previously'];
}}
var person = NewPerson(personObject, false);
person.save(function(err){
if(err){
console.log('database error');
throw err;
}
console.log('cropped document saved.');
});
Now until this point, all is well; problem is, that in the future my users would want to make edits/add new data such as new houses/family etc, how do I do it?
I mean, I already coded a form submission which sends their mongodb id, with that id I want to access the document they saved inside my people collection(I know how to access a document using the function findOne), and then push their new form data to keys, houses, family arrays and finally save it in the database.
Thank you for your time.
or you can just use update() method,this approach can modify the data in the mongodb, you do not need find it, change it and save it.
Related
I have an update endpoint that when an incoming (request) contains a site name that matches any site name in my job site's table, I change all those particular DB entries status to "Pending Transfer" and essentially clear their site location data.
I've been able to make this work with the following:
async function bulkUpdate(req, res){
const site = req.body.data;
const data = await knex('assets')
.whereRaw(`location ->> 'site' = '${site.physical_site_name}'`)
.update({
status: "Pending Transfer",
location: {
site: site.physical_site_name,
site_loc: { first_octet: site.first_octet, mdc: '', shelf: '', unit: ''} //remove IP address
},
//history: ''
}) //todo: update history as well
.returning('*')
.then((results) => results[0]);
res.status(200).json({ data });
}
I also want to update history (any action we ever take on an object like a job site is stored in a JSON object, basically used as an array.
As you can see, history is commented out, but as this function essentially "sweeps" over all job sites that match the criteria and makes the change, I would also like to "push" an entry onto the existing history column here as well. I've done this in other situations where I destructure the existing history data, and add the new entry, etc. But as we are "sweeping" over the data, I'm wondering if there is a way to just push this data onto that array without having to pull each individual's history data via destructuring?
The shape of an entry in history column is like so:
[{"action_date":"\"2022-09-06T22:41:10.232Z\"","action_taken":"Bulk Upload","action_by":"Davi","action_by_id":120,"action_comment":"Initial Upload","action_key":"PRtW2o3OoosRK9oiUUMnByM4V"}]
So ideally I would like to "push" a new object onto this array without having (or overwriting) the previous data.
I'm newer at this, so thank you for all the help.
I had to convert the column from json to jsonb type, but this did the trick (with the concat operator)...
history: knex.raw(`history || ?::jsonb`, JSON.stringify({ newObj: newObjData }))
To summarize, I am working with 2 collections - 'usercollection' and 'groupcollection' and I would like to associate users with groups. I don't want to have 2 copies of all the user documents so I have a unique ID attribute for each user that I want to use to associate specific users with specific groups. This is all running on a localhost webserver so I'm getting the input from an html page with a form in it where you enter 'username' and 'groupname'. I tried using the .distinct() function with query as 'username' and the target field/attribute as 'uid'.
// Set our internal DB variable
var db = req.db;
// Get our form values. These rely on the "name" attributes
var userName = req.body.username;
// Set query and options for searching usercollection
var query = {"username" : userName};
const fieldName = "uid";
// Set our collections
var users = db.get('usercollection');
// Get UID corresponding to username
var uidToAdd = users.distinct(fieldName, query);
This is what I attempted (with some other lines that aren't relevant taken out) but it just returned a null object so I'm at a bit of a loss. Also, I'm still a beginner with nodejs/javascript/mongoDB so the more informative the answer the better! When I do the same code in the mongo shell I can get the actual value of the 'uid' attribute so I really don't know what's going wrong
I am not sure I am following you. But if I understood correctly, if you want to make a relationship between 'usercollection' and 'groupcolletion', you can simply create those 2 collections and each user in 'usercollection' should have a field with 'groupid' as a reference. In this way, you can access 'groupcollection' easily.
Here is an example with using mongoose.
In User model
...
groupId: {
type: mongoose.Schema.Types.ObjectID
ref: "Group"
}
...
Later you can also use 'populate' to fetch 'Group' information.
...
let data = await User.findById(id).populate('groupId');
...
We need to update the all the documents in a collection to change their shape. We'd like to record an audit of the change in a different collection where we will store a document which contains the old and new version. In order to make this change atomic, we are using a stored proc.
The issue we are facing is updating another collection from a stored proc. It seems the audit document is always written into the collection the stored proc belongs to.
I have written up a sample stored proc:
function sample(prefix) {
var context = getContext();
var fooCollection = context.getCollection();
var barCollection = context.getCollection("BarCollection");
// Query documents and take 1st item.
var isAccepted = fooCollection.queryDocuments(
fooCollection.getSelfLink(),
'SELECT * FROM root r',
function (err, feed, options) {
if (err) throw err;
// Check the feed and if empty, set the body to 'no docs found',
// else take 1st element from feed
if (!feed || !feed.length) context.getResponse().setBody('no docs found');
else {
var fooDoc = feed[0];
var barDoc = {
"foo" : fooDoc,
"bar" : "bar"
}
var isAccepted2 = barCollection.createDocument(barCollection.getSelfLink(), barDoc);
if (!isAccepted2) throw new Error('The query was not accepted by the server.');
}
});
if (!isAccepted) throw new Error('The query was not accepted by the server.');
}
In this sample, my stored proc is saved in the FooCollection. I get a document and try to save a copy into the BarCollection. The new document is always saved into the FooCollection.
Is this scenario supported in Document DB? If so, what changes do I need to make the stored proc to make it work?
DocumentDB stored procedures are collection-scoped. You will not be able to write audit info to a separate collection; you'd need to write to the same collection.
I need to connect 2 queries in Parse.com with an and, my code is:
var queryDeseo1 = new Parse.Query(DeseosModel);
queryDeseo1.equalTo("User", Parse.User.current());
queryDeseo1.equalTo("Deseo", artist);
queryDeseo1.find({...
The result of the .find is all the objects with User = Parse.User.current()) and all the objects with Deseo = artist but I want the objects with the two queries together:
User = Parse.User.current()) and Deseo = artist
You've actually got it setup correctly to do an AND query. The problem (assuming that your data structure is setup properly) is that your User field is a Pointer to the User table. Therefore, you need to query for a User equal to the pointer, as opposed to a User equal to Parse.User.current() which will return a string. Something like the following:
var userPointer = {
__type: 'Pointer',
className: 'User',
objectId: Parse.User.current().id
}
queryDeseo1.equalTo('User', userPointer);
I have a Class in parse, say Pictures. Each of these belongs to a user. Reference to this user is stored in the Pictures table/class as a Pointer to the user.
In my cloud code I am trying to get all Pictures belonging to a user, using master key. Following is my code:
Parse.Cloud.define("getPictures", function(request, response) {
Parse.Cloud.useMasterKey();
var query = new Parse.Query("Pictures");
query.equalTo("user", request.params.user);
query.find({
success: function(results) {
var status = "Found " + results.length + " pictures for userId " + request.params.user;
response.success(status);
},
error: function() {
status = "No pictures exist for userId " + request.params.user;
response.error(status);
}
});
});
This code outputs that there are 0 pictures for a certain user with id 'xyz' for example. However, I can see that the user has a lot of pictures stored.
I have also verified that the problem is not with using master key, as I see in the console log that the code is being executed as master. Moreover, if I query for a picture by objectId, it does come out in the results, which means ACL is not the problem here.
I think I have to use relations/joining here, but I am not sure how to do that.
Pointers are stored as objects in Parse database, so if you try to compare a string to an object with query.equalTo() function, nothing will be found. This is how pointers are stored:
{
__type: 'Pointer',
className: '_User',
objectId: user-object-id
}
If you are querying a class with pointers and want your result comes with the whole object nested, you should set this in your query:
var query = new Parse.Query('Pictures');
query.include('user');
In my queries when I want to search by a pointer column, I compare my user object with the nested user object.
var user = new Parse.User();
// Set your id to desired user object id
user.id = your-user-id;
var query = new Parse.Query('Pictures');
// This include will make your query resut comes with the full object
// instead of just a pointer
query.include('user');
// Now you'll compare your local object to database objects
query.equalTo('user', user);
query.find({
success: function(userPicture) {
response.success(userPicture);
}
});
Anyway, seems that if you have many pictures related to an user, you probably are searching for parse relations instead of pointers: https://www.parse.com/docs/relations_guide
If you write a query to retrieve a parent object and a child object to which you have pointer, but no read access as per ACL, then the query may return only parent object and child will be null because the ACL wont let you read it.
There may be a problem with your params. If "user" is a pointer, then 'request.params.user' is incorrect, because PFObjects may not be sent as params. If "user" is a pointer, use 'request.user'. If request.params.user is a string of the userId, you could use the Id to reconstruct a PFObject shell before the query as was suggested by Murilo already, but deleting the "user" param and using request.user would shorten your code and not duplicate any values. Murilo's solution is also beneficial because you could pass a userId other than the current user's Id.