I'm new to MongoDB, and trying to reorder an array in a db.
Here's the schema:
headline: String,
Galleryslides: [{type: ObjectId, ref: 'Galleryslide'}],
Here's the logic I'm using. By the way, correctOrder is an array with the new order of ids for the DB.
Gallery.findById(req.params.galleryId, function(err, gallery) {
var newArr = [];
req.body.ids.forEach(function(id, index) {
newArr[index] = Galleryslides.find({"_id" : id});
});
gallery.Galleryslides = newArr;
gallery.save(function() {
res.json({status: 'ok'});
});
});
When this runs, nothing happens - the order of the array in the DB does not change. D'you know a better way to do this?
In mongodb, the records are sorted in natural order. You should get them in the same order you inserted but that's not guaranteed.
Like the docs say :
This ordering is an internal implementation feature, and you should
not rely on any particular structure within it.
If you want to sort by the _id field, you can do that(it will sort by the _id index) :
Gallery.find().sort({ "_id": 1 })
Related
// my db structure now
rcv : {
visible: 'all',
ids: [
[0] : userId,
[1] : user2Id ]
}
this is how i query to get the data it works.
//service.ts
getAlbumByUserId(userId) {
return this.afs.collection('albums', ref => ref.where('rcv.visible', '==', 'all').where('rcv.ids', 'array-contains', userId)).valueChanges();
}
//component.ts
this.service.getAlbumByUserId(this.userId);
but i want to set the structure like this but i don't know how to query nested objects in firebase
// database structure
rcv : {
visible: 'all',
ids: {
userId: {
id: userId
}
user2Id: {
id: user2Id
}
}
}
You're looking for the array-contains operator, which can check if a field that is an array contains a certain value.
You're already using the correct array-contains operator, but not with the correct syntax. The array-contains operator checks whether any element of your array is exactly the same as the value you pass in. So you need to pass in the complete value that exists in the array:
ref.where('rcv.visible', '==', 'all').where('rcv.ids', 'array-contains', { id: userId })
As you add more data to the array, it may become unfeasible to reproduce the entire array element for the query. In that case, the common approach is to add an additional field where you keep just the IDs.
So you'd end up with one field (say rcv.users) where you keep all details about the receiving users, and one field (say rcv.ids) where you just keep their IDs, and that you use for querying.
Is there a way to sort by a given array?
something like this:
const somes = await SomeModel.find({}).sort({'_id': {'$in': [ObjectId('sdasdsd), ObjectId('sdasdsd), ObjectId('sdasdsd)]}}).exec()
What i looking for is a way to get a solution, to get all document of the collection and sort by if the document's _id match with one of the given array.
An example:
we have albums collection and songs collection. In albums collection we store the ids of the songs that belongs to the albums.
I want to get the songs, but if the song is in the album take them front of the array.
I solved this as follow, but its looks a bit hacky:
const songs = await SongMode.find({}).skipe(limit * page).limit(limit).exec();
const album = await AlbumModel.findById(id).exec();
if(album) {
songArr = album.songs.slice(limit * page);
for(let song of album.songs) {
songs.unshift(song);
songs.pop();
}
}
This cannot be accomplished using an ordinary .find().sort(). Instead, you will need to use the MongoDB aggregation pipeline (.aggregate()). Specifically, you will need to do the following:
Perform a $projection such that if the _id is $in the array, your new sort_field is given the value 1, otherwise it's given a value of 0.
Perform a $sort such that you're doing a descending sort on the new sort_field.
If you're using MongoDB version 3.4 or greater, then this is easy because of the $addFields operator:
const your_array_of_ids = [
ObjectId('objectid1'),
ObjectId('objectid2'),
ObjectId('objectid3')
];
SomeModel.aggregate([
{ '$addFields': {
'sort_field': { '$cond': {
'if': { '$in': [ '$_id', your_array_of_ids ] },
'then': 1,
'else': 0
}}
}},
{ '$sort': {
'sort_field': -1
}}
]);
If you're using an older version of MongoDB, then the solution is similar, but instead of $addFields you will be using $project. Additionally, you will need to explicitly include all of the other fields you want included, otherwise they will be excluded from the results.
I have a Node backend server, connected to a MongoDB database. Here I have a patients collections containing patients object. I'm trying to update an attribute called position on each object.
I have started by retrieving the documents from MongoDB:
const patientsToChange = await Patient.find()
Then I'm trying to update some attributes in the array by iteration over the array.
patientsToChange.forEach(function (patient) {
patient.queuePosition = parseInt(patient.queuePosition) + 1
console.log(patient._id)
let updatedPatient = patient.update({ _id: patient._id }, patient)
})
What am I missing here?
Is it even possible to update in a forEach loop?
instead of patient.update you should use Patient.update. Also it is better to use $inc for incrementing one field:
Patient.updateOne({ _id: patient._id }, { $inc: { queuePosition }} )
I have two collections in my application that are parsed from two separate json files. I have inserted data from the two files into separate collections. The collections have corresponding numerical ID's and I want to match them up in a new collection. For example: the postmeta collection has a post_id value and the posts collection has a corresponding ID.
To explain this further here is a simple collections example. One thing to note is that there are over 730 collection posts and although there are matching ID's they are not sorted so when I view them they don't match each other.
The posts collection example:
{
"_id": "kTeQxenYZcQfPiaYv",
"ID": "44",
"post_content": "Today we talked about the letter Hh..."
}
The postsmeta collection example:
{
"_id": "otEGQYxvv6MkCABST",
"post_id": "44",
"meta_value": "http://www.mrskitson.ca/wp-content/uploads/2010/11/snackTime.jpg"
}
What I would like to do is parse through the collections and take for example posts collection where the ID matches the postsmeta collection. Once I find a match I want to insert the collections content (post_content & meta_value) into a new collection.
Here is all my code so far.
lib/collections/posts.js
Postsmeta = new Mongo.Collection('postsmeta');
Posts = new Mongo.Collection('posts');
server/publications.js
Meteor.publish('postsmeta', function() {
return Postsmeta.find();
});
Meteor.publish('posts', function() {
return Posts.find();
});
server/main.js
Meteor.startup(() => {
var postsmeta = JSON.parse(Assets.getText('postsmeta.json'));
var posts = JSON.parse(Assets.getText('posts.json'));
var length = postsmeta.length;
for(x=0; x < length; x++){
Posts.insert({
ID: posts[x].ID,
post_content: posts[x].post_content
});
Postsmeta.insert({
post_id: postsmeta[x].post_id,
meta_value: postsmeta[x].meta_value
});
}
});
Let's refactor your code a bit. We'll build the Postsmeta collection first and then jointly create the Posts and PostsCombined collections. Since Postsmeta will already exist we can just search inside it to find matching documents.
Meteor.startup(() => {
const postsmeta = JSON.parse(Assets.getText('postsmeta.json'));
postsmeta.forEach(doc => {
Postsmeta.insert({ post_id: doc.post_id, meta_value: doc.meta_value });
});
const posts = JSON.parse(Assets.getText('posts.json'));
posts.forEach(doc => {
const post = { ID: doc.ID, post_content: doc.post_content}
Posts.insert(post); // omit if you don't need the uncombined collection
const metadoc = Postsmeta.findOne({post_id: doc.ID}); // essentially a JOIN
if (metadoc) post.meta_value = metadoc.meta_value; // guard against no matching meta
PostsCombined.insert(post);
});
});
The following IDs are not present in your postsmeta data:
["56", "322", "521", "563", "583", "608", "625", "671", "707", "708",
"711", "713", "754", "758", "930", "1068", "1126", "1235", "1237", "1238",
"1239", "1246", "1249", "1256", "1263", "1355", "1375", "1678", "1680", "1763",
"1956", "2107", "2121", "2148", "2197", "2249"]
Do you want to put the collections together for consultation? because the insertion is correct for two different collections.
Tip one
If it is for query use the "find().map()", if you are using mongodb, within the function it will return the values of each row of the first collection and soon you can call the other collection and check the id of the collection and return a JSON or Array of what you need. I do not pretend to do it that way, but it's a way of putting the two collections together.
Best solution
The correct way is not thinking as if noSql was a relational database like the other postgres, mysql and etc ... think that it is a dynamic bank, where in the same collection you can have everything you need at that moment, so I think You create a new collection that would be the junction of the two, when save saves the data in this other collection, which would be the query collection, and in that it would weigh less the query and until it would return the data faster, but suppose a 5x more faster than the above example ...
I hope I have helped, any questions or doubts I will be here. Hugs!
I work with nodejs/express/mongoose/angularjs. I'd like to update a collection named Lists which has several properties, one of which is an array of items. In the following code, I'm pushing a new task items in the items array. Everything works fine, however the update function does not sends back the updated collection, then I must perform another query on the database. Is there a more efficient way to do this ?
The nodejs/express code :
exports.addTaskToList = function(req, res) {
var listId = req.params.Id;
var taskId = req.params.TaskId;
Lists.update({_id: listId}, {$push: {items: taskId}}, {safe:true, upsert: true}, function(err, result){
if(err) {
console.log('Error updating todo list. ' + err);
}
else{
console.log(result + ' todo list entry updated - New task added');
Lists.findById(listId).populate('items').exec(function (err, updatedEntry) {
if (err) {
console.log('Unable to retrieve todo list entry.');
}
res.send(JSON.stringify(updatedEntry));
});
}
});
};
Furthermore, the array items is an array of ObjectIds. Those items are in a separate schema so in a separate collection. Is it possible to push the whole object and not only its _id so that there is not another collection created ?
use findOneAndUpdate() method and in query parameter use option as { "new": true}
return this.sessionModel
.findOneAndUpdate({user_id: data.user_id}, {$set:{session_id: suuid}}, { "new": true})
.exec()
.then(data=>{
return {
sid: data.session_id
}
})
The update method doesn't return the updated document:
However, if we don't need the document returned in our application and
merely want to update a property in the database directly,
Model#update is right for us.
If you need to update and return the document, please consider one of the following options:
Traditional approach:
Lists.findById(listId, function(err, list) {
if (err) {
...
} else {
list.items.push(taskId)
list.save(function(err, list) {
...
});
}
});
Shorter approach:
Lists.findByIdAndUpdate(listId, {$push: {items: taskId}}, function(err, list) {
...
});
Regarding your last question:
Is it possible to push the whole object and not only its _id so that
there is not another collection created ?
The answer is yes. You can store sub-documents within documents quite easily with Mongoose (documentation on sub-documents here). By changing your schema a little, you can just push your whole item object (not just item _id) into an array of items defined in your List schema. But you'll need to modify your schema, for example:
var itemSchema = new Schema({
// Your Item schema goes here
task: 'string' // For example
});
var listSchema = new Schema({
// Your list schema goes here
listName: String, // For example...
items: [itemSchema] // Finally include an array of items
});
By adding an item object to the items property of a list, and then saving that list - your new item will be persisted to the List collection. For example,
var list = new List({
listName: "Things to do"
});
list.items.push({
task: "Mow the lawn"
});
list.save(function(error, result) {
if (error) // Handle error
console.log(result.list) // Will contain your item instance
});
So when you load your list, the items property will come pre-populated with your array of items.
This is because Items will no longer persist it a separate collection. It will be persisted to the List collection as a sub-document of a List.