I've got such User object:
{
"_id": "584d91ff6c751769fab91be5",
"username": "svit",
"name": "Ilya",
"role": "user",
"authData": [
{
"fb": {
"access_token": "susdfg",
"expiration_date": 1,
"id": "1187410264678321"
}
}
],
"__v": 9,
"currentToken": "9735f44f1c4371f143747ff670b0076148053f391ab866bafab7c6eaf47d295b"
}
I am interested in updating User.authData.fb. I tried that:
var curUser = userModel.findOne({_id: user._id}, function(err, curUser){
curUser['authData'][socialType] = {
access_token: socialToken,
expiration_date: 173249700 //TODO: normal date
};
curUser.set('currentToken', tokenName);
curUser.markModified('authData');
curUser.save();
});
But that does just nothing. It modifies currentToken, but not authData.
Also, I tried curUser.set('authData.fb.expiration_date", 173249700)
That does not works too.
I really need your help!
Best regards,
Ilya
You can loop through the 'authData' array and modify whatever values you may like. I am assuming authData is a array of socialTypes and it has an attribute name to indentify.
example:
var curUser = userModel.findOne({_id: user._id}, function(err, curUser){
curUser.authData.map(socialType => {
// Select the type of socialAuth you want to modify
if(socialType.name === 'fb') {
access_token: socialToken,
expiration_date: 173249700 //TODO: normal date
}
})
curUser.set('currentToken', tokenName);
curUser.markModified('authData');
curUser.save();
});
Related
I am using Mongo DB Atlas with node.js and oboe (oboe streams the results to html). I am new to this all, just learning all these technologies, so explaining in simpler terms will be appreaciated.
The goal is to do a $lookup between two collections, in this case, the collection of 'review' to 'place'. I've researched similar answers, but the either didn't work or were using strings, not ObjectIds.
It's quite simple, just connect the ObjectIds of both of the collections, but I am not able to pull the data out from the "left joined" collection of 'places' when using oboe (see oboe code at bottom, FWIW).
Here is a look at a document from both collections, then the code. What am I doing wrong? I have tried converting them to strings and joining with .toString() and .str, plus put 'place_id.ObjectId' and '_id.ObjectId' for localField and foreignField. Another thing too, is how can I see what is in the cursor to know what I am getting? debug(cursor.ToArray()) didn't work. Thanks in advance.
review
({
"_id": { "$oid": "5fd27fd9647f7bb815c4c946" },
"place_id": { "$oid": "5fbc37c4fc13ae680b00002b" }, // connect this...
"user_id": { "$oid": "5fbc10ecfc13ae232d000068" },
"title": "Black Forest -- unforgettable!",
"description": "The forest was great.",
"score": { "$numberInt": "5" }
}
place
{
"_id": { "$oid": "5fbc37c4fc13ae680b00002b" }, // connected to _id above
"name": "Black Forest (Schwarzwald)",
"category": "activity",
"city": "Freiburg",
"country": "Germany",
"description": "The Black Forest (German: Schwarzwald [ˈʃvaʁtsvalt] (About this soundlisten)) is a large forested mountain range.]",
"image": { "filename": "1607629020164_black_forest.jpg", "mime": "image/jpeg" },
"state": ""
})
router.get('/', async (req, res, next) => {
debug('get all reviews api');
try {
const q = req.query.q;
const collation = { locale: 'en_US', strength: 1 };
const matchStage = {};
if (q) {
matchStage.$text = { $search: q };
}
const pipeline = [
{
$match: matchStage,
},
{
$lookup: {
from: 'place',
localField: 'place_id',
foreignField: '_id',
as: 'place',
},
},
];
const connection = await db.connect();
const cursor = connection.collection('review').aggregate(pipeline, { collation: collation });
// write the JSON file
res.type('application/json');
res.write('[\n');
for await (const doc of cursor) {
res.write(JSON.stringify(doc));
res.write(',\n');
}
res.end('null]');
} catch (err) {
sendError(err, res);
}
});
The cursor goes to oboe and becomes an 'item'. I would expect to use a template string such as {item.place.name} to get the data when putting this into html. That's how I would access it, right?
const performSearch = () => {
seen = 0;
$('stream-data-spinner').removeClass('d-none');
$('#search-results').html('');
const formData = $('#search-place-form').serialize();
oboe('/api/review?' + formData)
.node('![*]', (item) => {
if (item) {
chunk.push(item);
if (chunk.length >= 1000) {
showChunk(chunk);
}
}
return oboe.drop;
})
.done((_) => {
// show the last chunk
showChunk(chunk);
// hide the spinner
outputSpinner.classList.add('d-none');
})
.fail((res) => {
// show the error
outputSeen.textContent = `ERROR: network error`;
outputSeen.classList.add('text-danger');
outputSpinner.classList.add('text-danger');
});
};
From your MongoDB aggregation query, your place field is an array. You may want to $unwind it to flatten it into object for your oboe code to access it.
I am trying to figure out how to update a nested array that is within an array with Mongoose. In my User collection, I have a customer array that contains customer info, along with a nested fleet array that holds the customer's fleet equipment. I am trying to update the fleet array via a PUT request, but am having difficulties.
I partially think it is not possible to update a nested array within an array like this, and maybe I should create a separate Schema for the customer and fleet. Anyways, here is what my User Schema looks like currently:
{
"username": "xps_maint",
"password": "0000",
"registerDate": "2018-10-24T13:37:12.093Z",
"_id": "5bd07612d63de74932734d92",
"customer": [
{
"name": "Freight Service ",
"email": "info#fsllc.com",
"dotInterval": "90 days",
"fleet": [
{
"unitType": "Box Truck",
"unitNumber": "BT-61318",
"vinNumber": "1XXXYYYUUUZZ3222",
"_id": "5bd0aef1e2abd64b12e0ab42"
},
{
"unitType": "Cargo Van",
"unitNumber": CV-78453",
"vinNumber": "4ZZYYYTTUZZ3JK2",
"_id": "5bd0aef1e2arg64b15e0ab43"
}
],
"_id": "5bd0821f79f9454b06b2c2bf"
}
],
"__v": 0
}
Here is my PUT route to update the fleet array:
router.put('/customers/fleet/:equipmentid', customer_controller.customer_update_fleet);
And finally here is the what the fleet update controller looks like:
exports.customer_update_fleet = (req, res) => {
const { body, params } = req;
const { unitType, unitNumber, vinNumber } = body;
const { equipmentid } = params;
const updatedEquipment =
{
unitType: unitType,
unitNumber: unitNumber,
vinNumber: vinNumber,
}
User.updateOne({ 'customer.$.fleet': { _id: equipmentid }}, { $set: { 'customer.$.fleet': { updatedEquipment} } }, (err) => {
if (err)
throw err;
else
res.send('Success!!');
});
}
I thought this might of worked, because I have a similar PUT route that updates just the customer array in the User Schema via Model.updateOne(). However this does not seem to work the same way when trying to go deeper into the nested fleet array within each customer.
I may be approaching this all wrong, so I am all ears on a better way to model the User Schema. I do partially think that it is not too good to have arrays nested deep in Schemas like this, they seem like a pain to update. Thanks in advance for reading!
I have seen similar questions asked, but those questions had slightly different data structures to what I'm dealing with. I've looked at:
Joining data between paths based on id using AngularFire
AngularFire2: Perform 'Joins' on FirebaseListObservables using RxJS .map()
This is my data structure:
{
"samples": {
"24084": {
"addInfo": "TEST",
"datePrinted": "8/11/2017 9:42:57 AM",
"equipment": "GR028",
"hmisNumber": "100E",
"lotNumber": "GR0030C659-JM",
"productionNumber": "PN0034781",
"userName": "MCorbett"
},
"24342": {
"addInfo": "test",
"datePrinted": "8/15/2017 11:51:55 AM",
"equipment": "GR025",
"hmisNumber": "100",
"lotNumber": "BR0010P835",
"productionNumber": "PN0035616",
"userName": "MCorbett"
}
},
"scans": {
"-Krlb3tv3oFPtYZp2ErX": {
"inTime": 1502997139131,
"sampleId": "24342"
},
"-KrlbdbCT0us6xE9POm3": {
"inTime": 1502997289573,
"outTime": 1502997292524,
"sampleId": "24342"
},
"-Krlc3vsjiQ9czWYGvA9": {
"inTime": 1502997401784,
"outTime": 1502997404864,
"sampleId": "24084"
}
}
}
As you can see, Samples to Scans have a one to many relationship. What I need to do is populated a table with Sample data joined to scan data. It needs to look like this:
"24342": {
"addInfo": "test",
"datePrinted": "8/15/2017 11:51:55 AM",
"equipment": "GR025",
"hmisNumber": "100",
"lotNumber": "BR0010P835",
"productionNumber": "PN0035616",
"userName": "MCorbett",
"inTime": 1502996197213
}
I need to grab all Scans where outTime is undefined, and then join it to it's corresponding Sample data. Here is what I have tried so far:
// Get samples that have a scan where inTime is populated but outTime is not
getOpenSamples() {
console.log('getopensmaples stareted')
let scanWithSampleList = this.scanSvc.getScansList({
orderBy: 'outTime',
startAt: ''
})
.switchMap(scans => {
let sampleObservables = scans.map(scan => this.getSample(scan.sampleId));
console.log("insisde");
return sampleObservables.length === 0 ?
Observable.of(scans) :
Observable.combineLatest(sampleObservables, (samples) => {
scans.forEach((scan, index) => {
scan.productionNumber = samples[index].productionNumer;
scan.lotNumbner = samples[index].lotNumber;
});
return scans;
});
});
}
This gives me this error:
ERROR in C:/Users/corbetmw/workspace/angular/sample-time-tracking/src/app/samples/shared/sample.service.ts (82,54): Propert
y 'productionNumer' does not exist on type '{}'.
What am I doing wrong here? This seems like a simple enough thing, but I'm having a lot of trouble with it. Do I need to change my data structure? Should I make a component that gets the Scans with undefined outTime and stick it in the table with a parent that can pass the sample ID, or vice versa?
I was able to find a solution which returns an observable of type Scan<> with a single Scan inside of it.
I have this function:
getOpenScans() {
const scansList = this.db.list('/scans', ref => ref.orderByChild('outTime').endAt(null));
return scansList.snapshotChanges().map(arr => {
return arr.map(snap => Object.assign(snap.payload.val(), {
$key: snap.key
}))
})
}
Then, I have this guy:
getOpenSamples() {
let openScans = this.scanSvc.getOpenScans();
let fullSamples = openScans.map(scans => {
for (let scan of scans) {
scan.sample = this.getSample(scan.sampleId);
}
return scans;
});
//fullSamples.subscribe(samples => console.log(samples));
return fullSamples;
}
I am now trying to implement this solution with MatTable in Material2.
I'm quite new with Mongoose, I'm trying to get familiar with it,but the poor documentation doesn't help (no search, no list of functions,..).
I have a document that represents a Company, and subdocuments that represents the users:
{
"_id": "57ffa47f5b70f90831212348",
"name": "mycompany",
"address": "...",
"phone": "...",
"users": [
{
"_id": "57ffa47f5b70f90831212347",
"username": "alpha",
"name": "myname",
"surname": "mysurname",
"password": "..."
}
]
}
I want to find a particular subdocument and update just some fields (name,surname, password,...) that are passed from frontend.
I receive req.body that contains the fields edited (i.e. req.body.name) and req.user that contains the user logged:
"company_shortname": "CMPNY",
"company_id": "57ffa47f5b70f90831212348",
"user": {
"id_access_level": 0,
"surname": "ltd",
"name": "mycompany",
"username": "mycompanyusername",
"_id": "57ffa47f5b70f90831212347",
"password": "..."
}
}
what I want to obtain is find the subdoc edited (the company that contains this subdoc will be always the same of the user logged in), update data passed, and save.
Using this answer, I tried:
Company.find({'_id': req.user.company_id}).select('name').exec(
function(err, company) {
if (err) res.status(500).send(err);
var partialUpdate = req.body;
var set = {};
for (var field in partialUpdate) {
set['users.$.' + field] = partialUpdate[field];
}
company.update({_id: req.user._id, "users._id": req.body._id},
{$set: set},
function(err, numAffected) {
console.log('Number of users edited: ' +JSON.stringify(numAffected,null,4));
});
});
but I cannot get it to work.. any ideas?
I solved using this query:
//saving in 'set' the fields to be edited
var partialUpdate = req.body;
var set = {};
for (var field in partialUpdate) {
set['users.$.' + field] = partialUpdate[field];
}
//find the company,then the subdoc, then set the fields with 'set'
Company.findOneAndUpdate({
'_id': req.user.company_id, "users._id" : req.body._id},
{$set: set},
function(err, company) {
//the company status after the update
console.log('company updated: ' +JSON.stringify(company,null,4));
});
I am using REST API(express.js and mongodb) and trying to update my document but it's not working. I don't know what is the error but can someone help me out to move forward? I have added my route and controller
Routes:
app.route('/articleupdation')
.post(article.updatearticle);
Controller:
exports.updatearticle = function(req, res) {
Article.findOne({
Username: 'xx',
Email: 'xx#gmail.com',
Info: 'Deactivate',
}, function(err, article) {
if (!err && article) {
article.Info = 'Active';
article.save(function(err) {
if (err) {
console.log('not working');
} else {
console.log('working');
}
});
} else {
console.log('Condtion not matched ');
console.log(err);
}
});
};
Data stored like this
{
"_id": {
"$oid": "5799995943d643600fabd6b7"
},
"Username": "xx",
"Email": "xx#gmail.com",
"Info": "Deactivate",
"Description": "aajdjdjddjdkjddjdjdhdj",
}
Here is what I am trying to achieve; if Username, Email, Info are matched I need to update article.Info = 'Active'; but this is not working, can someone help me out please?
From the looks of it, your query is not matching any documents in the collection hence the statement branch which does the update is not being reached, just the else statement as the returned article is null. You can test this by running the raw query in mongo shell on the underlying collection i.e.
db.articles.findOne({
"Username": "xx",
"Email": "xx#gmail.com",
"Info": "Deactivate"
})
and see if that returns any matching document. If not, check the Info field from the document returned in this query
db.articles.findOne({
"Username": "xx",
"Email": "xx#gmail.com"
})
The best way to go about this within an atomic update that does not require two requests to the server (i.e. one to query the document and the other to write the changes to the server) is to use the findOneAndUpdate api. This will issue a mongodb findAndModify update command which modifies and returns a single document. By default, the returned document does not include the modifications made on the update. To return the document with the modifications made on the update, use the new option.
Thus your refactored code could follow this pattern:
exports.updatearticle = function(req, res) {
Article.findOneAndUpdate(
{ "Username": req.body.username, "Email": req.body.email, "Info": "Deactivate" },
{ "$set": { "Info": "Active" } },
{ "new": true },
function (err, doc) {
if (err) { // err: any errors that occurred
console.log(err);
} else { // doc: the document before updates are applied if `new: false`
console.log(doc); // , the document returned after updates if `new true`
console.log(doc.Info);
}
}
);
};