如何根据Mongoose中的createdAt字段对数组中的对象进行排序?

huangapple go评论62阅读模式
英文:

How to sort object inside of array based on createdAt in mongoose?

问题

我正在尝试根据createdAt日期对products数组进行排序。

我的订单模型

const itemSchema = new Schema(
    {
        productId: { type: Schema.Types.ObjectId, ref: 'Product' },
        quantity: {
            type: Number,
            max: [10, '只能添加10个数量的物品。'],
            required: true,
        },
        price: { type: Number, required: true },
    },
    { timestamps: true }
);

const ordersSchema = new Schema({
    products: [itemSchema],
    userId: { type: Schema.Types.ObjectId, ref: 'User' },
});

我根据一个Stack Overflow的帖子尝试了这个:

const orders = await Order.findOne({ userId: req.userId })
        .sort({ 'products.createdAt': -1 })
        .slice('products', 10)
        .populate({ path: 'products.productId', select: 'images title' });

但它没有返回排序后的数组。

英文:

I am trying to sort the products array based on the createdAt date.

My orders model

const itemSchema = new Schema(
    {
        productId: { type: Schema.Types.ObjectId, ref: 'Product' },
        quantity: {
            type: Number,
            max: [10, 'Only 10 quantity of one item can be added.'],
            required: true,
        },
        price: { type: Number, required: true },
    },
    { timestamps: true }
);

const ordersSchema = new Schema({
    products: [itemSchema],
    userId: { type: Schema.Types.ObjectId, ref: 'User' },
});

I tried this according to a stack overflow post

 const orders = await Order.findOne({ userId: req.userId })
        .sort({ 'products.createdAt': -1 })
        .slice('products', 10)
        .populate({ path: 'products.productId', select: 'images title' });

But it does not return sorted array.

答案1

得分: 2

If you run current version (6.0) of MongoDB, then you can use $sortArray:

db.collection.aggregate([
  {
    $set: {
      products: {
        $sortArray: {
          input: "$products",
          sortBy: { createdAt: 1 }
        }
      }
    }
  }
])

Mongo Playground

英文:

If you run current version (6.0) of MongoDB, then you can use $sortArray:

db.collection.aggregate([
  {
    $set: {
      products: {
        $sortArray: {
          input: "$products",
          sortBy: { createdAt: 1 }
        }
      }
    }
  }
])

Mongo Playground

答案2

得分: 1

db.collection.aggregate([
  {
    "$unwind": "$products"
  },
  {
    "$sort": {
      "products.createdAt": -1
    }
  },
  {
    "$group": {
      _id: "$_id",
      products: {
        "$push": "$products"
      }
    }
  }
])
[
  {
    "_id": ObjectId("5a934e000102030405000000"),
    "products": [
      {
        "createdAt": "2023-07-03",
        "productId": "3"
      },
      {
        "createdAt": "2023-07-02",
        "productId": "1"
      },
      {
        "createdAt": "2023-07-01",
        "productId": "2"
      }
    ]
  }
]

Mongoose(v7.3.4) 示例:

import mongoose from 'mongoose';
import util from 'util';
import { config } from '../../config';

mongoose.set('debug', true);
console.log(mongoose.version);

const productSchema = new mongoose.Schema({
  title: String,
  images: [],
});
const Product = mongoose.model('Product', productSchema);

const itemSchema = new mongoose.Schema(
  {
    productId: { type: mongoose.Schema.Types.ObjectId, ref: 'Product' },
  },
  { timestamps: true },
);
const Item = mongoose.model('Item', itemSchema);

const ordersSchema = new mongoose.Schema({
  products: [itemSchema],
});
const Orders = mongoose.model('Orders', ordersSchema);

(async function main() {
  try {
    await mongoose.connect(config.MONGODB_URI);
    await Promise.all([Product, Item, Orders].map((m) => m.collection.drop()));
    // 种子数据
    const [p1, p2, p3] = await Product.create([
      { title: 'product a', images: ['a', 'b'] },
      { title: 'product b', images: ['c', 'd'] },
      { title: 'product c', images: ['e', 'f'] },
    ]);
    const items = await Item.create([
      { productId: p1, createdAt: new Date(2023, 6, 4) },
      { productId: p3, createdAt: new Date(2023, 6, 3) },
      { productId: p2, createdAt: new Date(2023, 6, 5) },
    ]);
    const [o1] = await Orders.create([{ products: items }]);

    // 测试
    const r = await Orders.aggregate()
      .match({ _id: o1?._id })
      .unwind('products')
      .lookup({
        from: 'products',
        localField: 'products.productId',
        foreignField: '_id',
        as: 'lookup_products',
      })
      .unwind('lookup_products')
      .addFields({ 'products.title': '$lookup_products.title', 'products.images': '$lookup_products.images' })
      .sort({ 'products.createdAt': -1 })
      .group({ _id: '$_id', products: { $push: '$products' } })
      .project({ lookup_products: 0 });

    console.log(util.inspect(r, false, null));
  } catch (error) {
    console.error(error);
  } finally {
    await mongoose.connection.close();
  }
})();

日志:

[
  {
    _id: new ObjectId("64b4e66fdafc40c3caae9ee5"),
    products: [
      {
        productId: new ObjectId("64b4e66edafc40c3caae9eda"),
        _id: new ObjectId("64b4e66fdafc40c3caae9ee1"),
        createdAt: 2023-07-04T16:00:00.000Z,
        updatedAt: 2023-07-04T16:00:00.000Z,
        __v: 0,
        title: 'product b',
        images: [ 'c', 'd' ]
      },
      {
        productId: new ObjectId("64b4e66edafc40c3caae9ed9"),
        _id: new ObjectId("64b4e66fdafc40c3caae9edf"),
        createdAt: 2023-07-03T16:00:00.000Z,
        updatedAt: 2023-07-03T16:00:00.000Z,
        __v: 0,
        title: 'product a',
        images: [ 'a', 'b' ]
      },
      {
        productId: new ObjectId("64b4e66edafc40c3caae9edb"),
        _id: new ObjectId("64b4e66fdafc40c3caae9ee0"),
        createdAt: 2023-07-02T16:00:00.000Z,
        updatedAt: 2023-07-02T16:00:00.000Z,
        __v: 0,
        title: 'product c',
        images: [ 'e', 'f' ]
      }
    ]
  }
]

<details>
<summary>英文:</summary>
```ts
db.collection.aggregate([
{
&quot;$unwind&quot;: &quot;$products&quot;
},
{
&quot;$sort&quot;: {
&quot;products.createdAt&quot;: -1
}
},
{
&quot;$group&quot;: {
_id: &quot;$_id&quot;,
products: {
&quot;$push&quot;: &quot;$products&quot;
}
}
}
])

mongoplayground

Input:

[
  {
    userId: &quot;1&quot;,
    products: [
      {
        productId: &quot;1&quot;,
        createdAt: &quot;2023-07-02&quot;
      },
      {
        productId: &quot;2&quot;,
        createdAt: &quot;2023-07-01&quot;
      },
      {
        productId: &quot;3&quot;,
        createdAt: &quot;2023-07-03&quot;
      },
      
    ]
  }
]

Output:

[
  {
    &quot;_id&quot;: ObjectId(&quot;5a934e000102030405000000&quot;),
    &quot;products&quot;: [
      {
        &quot;createdAt&quot;: &quot;2023-07-03&quot;,
        &quot;productId&quot;: &quot;3&quot;
      },
      {
        &quot;createdAt&quot;: &quot;2023-07-02&quot;,
        &quot;productId&quot;: &quot;1&quot;
      },
      {
        &quot;createdAt&quot;: &quot;2023-07-01&quot;,
        &quot;productId&quot;: &quot;2&quot;
      }
    ]
  }
]

Mongoose(v7.3.4) example :

import mongoose from &#39;mongoose&#39;;
import util from &#39;util&#39;;
import { config } from &#39;../../config&#39;;

mongoose.set(&#39;debug&#39;, true);
console.log(mongoose.version);

const productSchema = new mongoose.Schema({
	title: String,
	images: [],
});
const Product = mongoose.model(&#39;Product&#39;, productSchema);

const itemSchema = new mongoose.Schema(
	{
		productId: { type: mongoose.Schema.Types.ObjectId, ref: &#39;Product&#39; },
	},
	{ timestamps: true },
);
const Item = mongoose.model(&#39;Item&#39;, itemSchema);

const ordersSchema = new mongoose.Schema({
	products: [itemSchema],
});
const Orders = mongoose.model(&#39;Orders&#39;, ordersSchema);

(async function main() {
	try {
		await mongoose.connect(config.MONGODB_URI);
		await Promise.all([Product, Item, Orders].map((m) =&gt; m.collection.drop()));
		// seed
		const [p1, p2, p3] = await Product.create([
			{ title: &#39;product a&#39;, images: [&#39;a&#39;, &#39;b&#39;] },
			{ title: &#39;product b&#39;, images: [&#39;c&#39;, &#39;d&#39;] },
			{ title: &#39;product c&#39;, images: [&#39;e&#39;, &#39;f&#39;] },
		]);
		const items = await Item.create([
			{ productId: p1, createdAt: new Date(2023, 6, 4) },
			{ productId: p3, createdAt: new Date(2023, 6, 3) },
			{ productId: p2, createdAt: new Date(2023, 6, 5) },
		]);
		const [o1] = await Orders.create([{ products: items }]);

		// test
		const r = await Orders.aggregate()
			.match({ _id: o1?._id })
			.unwind(&#39;products&#39;)
			.lookup({
				from: &#39;products&#39;,
				localField: &#39;products.productId&#39;,
				foreignField: &#39;_id&#39;,
				as: &#39;lookup_products&#39;,
			})
			.unwind(&#39;lookup_products&#39;)
			.addFields({ &#39;products.title&#39;: &#39;$lookup_products.title&#39;, &#39;products.images&#39;: &#39;$lookup_products.images&#39; })
			.sort({ &#39;products.createdAt&#39;: -1 })
			.group({ _id: &#39;$_id&#39;, products: { $push: &#39;$products&#39; } })
			.project({ lookup_products: 0 });

		console.log(util.inspect(r, false, null));
	} catch (error) {
		console.error(error);
	} finally {
		await mongoose.connection.close();
	}
})();

Logs:

[
  {
    _id: new ObjectId(&quot;64b4e66fdafc40c3caae9ee5&quot;),
    products: [
      {
        productId: new ObjectId(&quot;64b4e66edafc40c3caae9eda&quot;),
        _id: new ObjectId(&quot;64b4e66fdafc40c3caae9ee1&quot;),
        createdAt: 2023-07-04T16:00:00.000Z,
        updatedAt: 2023-07-04T16:00:00.000Z,
        __v: 0,
        title: &#39;product b&#39;,
        images: [ &#39;c&#39;, &#39;d&#39; ]
      },
      {
        productId: new ObjectId(&quot;64b4e66edafc40c3caae9ed9&quot;),
        _id: new ObjectId(&quot;64b4e66fdafc40c3caae9edf&quot;),
        createdAt: 2023-07-03T16:00:00.000Z,
        updatedAt: 2023-07-03T16:00:00.000Z,
        __v: 0,
        title: &#39;product a&#39;,
        images: [ &#39;a&#39;, &#39;b&#39; ]
      },
      {
        productId: new ObjectId(&quot;64b4e66edafc40c3caae9edb&quot;),
        _id: new ObjectId(&quot;64b4e66fdafc40c3caae9ee0&quot;),
        createdAt: 2023-07-02T16:00:00.000Z,
        updatedAt: 2023-07-02T16:00:00.000Z,
        __v: 0,
        title: &#39;product c&#39;,
        images: [ &#39;e&#39;, &#39;f&#39; ]
      }
    ]
  }
]

huangapple
  • 本文由 发表于 2023年7月17日 13:46:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/76701765.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定