I have two collections in a Meteor project, loosely created like this:
ItemContainer.insert({
title: title,
items: [],
});
Items.insert({
title: title,
});
Whenever a new Item is created it's id is added to the items array in an ItemContainer.
I also have a helper like this:
Template.body.helpers() {
items() {
const instance = Template.instance();
const containerId = instance.state.get("currentContainer");
const theseItems = ItemContainer.find({ _id: containerId}).items;
return Items.find({ _id: { $in: items } });
}
}
The issue is that I want to sort the items that I'm returning by their index in the items array. So when I generate a list of items in the browser then the item whose id is at items[0] gets displayed first, followed by items[1] and so on. Unfortunately I can't find a simple solution in the Mongo docs.
I can think of some ways to do that, like constructing an object by iterating over the items array and returning that, but I have to imagine there's a simpler way. It's also possible for the number of items to grow quite large, in theory thousands or tens of thousands.
Anybody know an easy way to sort by array index?
You can try to sort items in ascending order when finding through ItemContainer. So that items are returned correct order.
const theseItems = ItemContainer.find({ _id: containerId}).sort({"items.0": 1}).items;
Related
Alright, so I have a collection called Polls. Inside the Polls "table" there is an attribute called choiceObjects which is an array of objects. Each object inside this array has its own attributes. What I need to do is update one of the attributes there. Ill give you a screen shot so you can better visualise what Im talking about
As you can see the choice objects have attributes like body, country etc. There is another attribute called pollid which is set to optional and therefore you cant see it right now. I need to update this pollid attribute now that I have acess to the pollid
Polls.update(
{ _id: pollId },
{ "$set": { "choiceObjects": { pollid: pollId } } }
); //this is kind of what Im trying to do but this isnt right
Since then... I have further tried the following :
var selectedpoll = Polls.findOne(pollId);
console.log(selectedpoll);
//Polls.update( selectedpoll, {"$set"{'choiceObjects.$.pollId':pollId}},false, true );
but when i try that i get the error : the positional operator did not find the match needed from the query. unexpanded update: choiceObjects.$.pollId
If I understand your objective correctly, you want to update (or add) pollid to all objects in the choiceObjects array. Unfortunately $, $push, $addToSet only work with single elements AFAIK.
This might not be what you are looking for but one possible and very obvious way to approach this problem would be to update the entire array in the collection i.e.
var choiceObjects = Polls.findOne({_id: pollId}).choiceObjects;
for (var i = 0; i < choiceObjects.length; i++) {
choiceObjects[i].pollid = pollid;
}
Polls.update({_id: pollid}, {choiceObjects: choiceObjects});
The users table contains an items array which is just a collection of Item ObjectId's.
Users
{
state: 'active',
items: [ObjectId("4ecc05e55dd98a436ddcc47c"), ObjectId("4ecc05e55dd98a436ddcc47d")]
}
Items
{
name: 'weapon',
creator: 'mark'
}
I want to write a query that finds all users which have an item with creator 'mark'. Is that possible in one query? I tried something like this but it does not work.
{
'items.creator': 'mark
};
Firstly, you need to have the items collection either as embedded or reference. With this structure in mind, we can write the query as
db.Users.find({"items.creator" : 'mark'})
This is a part of my document:
var actions = {
title: 'Change of windows'
energySavings:[
{
_id: 234324234,
mainCategory: 'Elektricitet',
subCategory: 'Belysning',
value: 1
},
{
_id: 5434534543,
mainCategory: 'Elektricitet',
subCategory: 'Utrustning',
value: 1
}
]
}
I want to be able to update energySavings, add items and remove items. This could be done in three separate queries. Or, I could all do it in just one
var givenAction = JSON.parse(req.body.action);
mongoose.model('Action').findOne({actionId: req.params.actionId}, function(err, action){
action.energySavings = givenAction.energySavings;
action.save(function(err, savedAction){
res.status(200).send(savedAction);
});
})
Way less code then three separate queries. However, if the client side programmer makes a mistake, for example empty the entire array and save it, we will have a problem. Is there a best practice to this, make in one query or several with more control?
You can also update the document with findOneAndUpdate of mongoose. For case the empty array added mistakenly, you need to check if the query is empty or not before updating or adding that.
var givenAction = JSON.parse(req.body.action);
mongoose.model('Action').findOneAndUpdate({
actionId: req.params.actionId
}, {
$set: {
energySavings: givenAction.energySavings
}
}, callback);
You can use $push to add as new items, and $pull to remove items instead of $set to updating it. I don't think it is not a good choice to update energySavings, add items and remove items in one query.
in mongodb records are store like this
{_id:100,type:"section",ancestry:nil,.....}
{_id:300,type:"section",ancestry:100,.....}
{_id:400,type:"problem",ancestry:100,.....}
{_id:500,type:"section",ancestry:100,.....}
{_id:600,type:"problem",ancestry:500,.....}
{_id:700,type:"section",ancestry:500,.....}
{_id:800,type:"problem",ancestry:100,.....}
i want to fetch records in order like this
first record whose ancestry is nil
then all record whose parent is first record we search and whose type is 'problem'
then all record whose parent is first record we search and whose type is 'section'
Expected output is
{_id:100,type:"section",ancestry:nil,.....}
{_id:400,type:"problem",ancestry:100,.....}
{_id:800,type:"problem",ancestry:100,.....}
{_id:300,type:"section",ancestry:100,.....}
{_id:500,type:"section",ancestry:100,.....}
{_id:600,type:"problem",ancestry:500,.....}
{_id:700,type:"section",ancestry:500,.....}
Try this MongoDB shell command:
db.collection.find().sort({ancestry:1, type: 1})
Different languages, where ordered dictionaries aren't available, may use a list of 2-tuples to the sort argument. Something like this (Python):
collection.find({}).sort([('ancestry', pymongo.ASCENDING), ('type', pymongo.ASCENDING)])
#vinipsmaker 's answer is good. However, it doesn't work properly if _ids are random numbers or there exist documents that aren't part of the tree structure. In that case, the following code would work rightly:
function getSortedItems() {
var sorted = [];
var ids = [ null ];
while (ids.length > 0) {
var cursor = db.Items.find({ ancestry: ids.shift() }).sort({ type: 1 });
while (cursor.hasNext()) {
var item = cursor.next();
ids.push(item._id);
sorted.push(item);
}
}
return sorted;
}
Note that this code is not fast because db.Items.find() will be executed n times, where n is the number of documents in the tree structure.
If the tree structure is huge or you will do the sort many times, you can optimize this by using $in operator in the query and sort the result on the client side.
In addition, creating index on the ancestry field will make the code quicker in either case.
suppose I have a collection with a following structure
{
'_id': 'some id',
'items': [item1, item2, ..., itemN]
}
....
can you help me, how I can find previous and next item if I know 'some id' and itemK
Of course I can just return all items and later parse them on server side.
But I think that there should be some solution
You can selectively return individual fields but I can't see how you could return individual elements from an array in a field, and certainly not using a query based on relative positions within that array.
Is the items field so large that you need to return less than the whole field?